/**
 * nmr-processing - Pure functions allowing to process NMR spectra.
 * @version v9.2.0
 * @link https://github.com/cheminfo/nmr-processing#readme
 * @license MIT
 */
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.nmrProcessing = {}));
})(this, (function (exports) { 'use strict';

    const gyromagneticRatio = {
      '1H': 267.52218744e6,
      '2H': 41.065e6,
      '3H': 285.3508e6,
      '3He': -203.789e6,
      '7Li': 103.962e6,
      '13C': 67.28284e6,
      '14N': 19.331e6,
      '15N': -27.116e6,
      '17O': -36.264e6,
      '19F': 251.662e6,
      '23Na': 70.761e6,
      '27Al': 69.763e6,
      '29Si': -53.19e6,
      '31P': 108.291e6,
      '57Fe': 8.681e6,
      '63Cu': 71.118e6,
      '67Zn': 16.767e6,
      '129Xe': -73.997e6
    };

    /* eslint-disable camelcase */
    const impurities = {
      cdcl3: {
        tms: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 0
        }],
        solvent: [{
          proton: 'X',
          coupling: 0,
          multiplicity: 'ds',
          shift: 7.26
        }],
        h2o: [{
          proton: 'H2O',
          coupling: 0,
          multiplicity: 'bs',
          shift: 1.56
        }],
        acetic_acid: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.1
        }],
        acetone: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.17
        }],
        acetonitrile: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.1
        }],
        benzene: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.36
        }],
        'tert-butyl_alcohol': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.28
        }],
        'tert-butyl_methyl_ether': [{
          proton: 'CCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.19
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.22
        }],
        bhtb: [{
          proton: 'ArH',
          coupling: 0,
          multiplicity: 's',
          shift: 6.98
        }, {
          proton: 'OHc',
          coupling: 0,
          multiplicity: 's',
          shift: 5.01
        }, {
          proton: 'ArCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.27
        }, {
          proton: 'ArC(CH3)3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.43
        }],
        chloroform: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.26
        }],
        cyclohexane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 1.43
        }],
        '1,2-dichloroethane': [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.73
        }],
        dichloromethane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 5.3
        }],
        diethyl_ether: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.21
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.48
        }],
        diglyme: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.65
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.57
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.39
        }],
        '1,2-dimethoxyethane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.4
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.55
        }],
        dimethylacetamide: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.09
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.02
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.94
        }],
        dimethylformamide: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 8.02
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.96
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.88
        }],
        dimethyl_sulfoxide: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.62
        }],
        dioxane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.71
        }],
        ethanol: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.25
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.72
        }, {
          proton: 'OH',
          coupling: 5,
          multiplicity: 's,t',
          shift: 1.32
        }],
        ethyl_acetate: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.05
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 4.12
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.26
        }],
        ethyl_methyl_ketone: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.14
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.46
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.06
        }],
        ethylene_glycol: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.76
        }],
        'grease^f': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 'm',
          shift: 0.86
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'br_s',
          shift: 1.26
        }],
        'n-hexane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 't',
          shift: 0.88
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.26
        }],
        hmpag: [{
          proton: 'CH3',
          coupling: 9.5,
          multiplicity: 'd',
          shift: 2.65
        }],
        methanol: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.49
        }, {
          proton: 'OH',
          coupling: 0,
          multiplicity: 's',
          shift: 1.09
        }],
        nitromethane: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 4.33
        }],
        'n-pentane': [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 7
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.27
        }],
        '2-propanol': [{
          proton: 'CH3',
          coupling: 6,
          multiplicity: 'd',
          shift: 1.22
        }, {
          proton: 'CH',
          coupling: 6,
          multiplicity: 'sep',
          shift: 4.04
        }],
        pyridine: [{
          proton: 'CH(2)',
          coupling: 0,
          multiplicity: 'm',
          shift: 8.62
        }, {
          proton: 'CH(3)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.29
        }, {
          proton: 'CH(4)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.68
        }],
        silicone_greasei: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 0.07
        }],
        tetrahydrofuran: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.85
        }, {
          proton: 'CH2O',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.76
        }],
        toluene: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.36
        }, {
          proton: 'CH(o/p)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.17
        }, {
          proton: 'CH(m)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.25
        }],
        triethylamine: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.03
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.53
        }]
      },
      '(cd3)2co': {
        tms: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 0
        }],
        solvent: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 2.05
        }],
        h2o: [{
          proton: 'H2O',
          coupling: 0,
          multiplicity: 's',
          shift: 2.84
        }],
        acetic_acid: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.96
        }],
        acetone: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.09
        }],
        acetonitrile: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.05
        }],
        benzene: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.36
        }],
        'tert-butyl_alcohol': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.18
        }],
        'tert-butyl_methyl_ether': [{
          proton: 'CCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.13
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.13
        }],
        bhtb: [{
          proton: 'ArH',
          coupling: 0,
          multiplicity: 's',
          shift: 6.96
        }, {
          proton: 'ArCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.22
        }, {
          proton: 'ArC(CH3)3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.41
        }],
        chloroform: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 8.02
        }],
        cyclohexane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 1.43
        }],
        '1,2-dichloroethane': [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.87
        }],
        dichloromethane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 5.63
        }],
        diethyl_ether: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.11
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.41
        }],
        diglyme: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.56
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.47
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.28
        }],
        '1,2-dimethoxyethane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.28
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.46
        }],
        dimethylacetamide: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.97
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.83
        }],
        dimethylformamide: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.96
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.94
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.78
        }],
        dimethyl_sulfoxide: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.52
        }],
        dioxane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.59
        }],
        ethanol: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.12
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.57
        }, {
          proton: 'OH',
          coupling: 5,
          multiplicity: 's,t',
          shift: 3.39
        }],
        ethyl_acetate: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.97
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 4.05
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.2
        }],
        ethyl_methyl_ketone: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.07
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.45
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.96
        }],
        ethylene_glycol: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.28
        }],
        'grease^f': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 'm',
          shift: 0.87
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'br_s',
          shift: 1.29
        }],
        'n-hexane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 't',
          shift: 0.88
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.28
        }],
        hmpag: [{
          proton: 'CH3',
          coupling: 9.5,
          multiplicity: 'd',
          shift: 2.59
        }],
        methanol: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.31
        }, {
          proton: 'OH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.12
        }],
        nitromethane: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 4.43
        }],
        'n-pentane': [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.88
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.27
        }],
        '2-propanol': [{
          proton: 'CH3',
          coupling: 6,
          multiplicity: 'd',
          shift: 1.1
        }, {
          proton: 'CH',
          coupling: 6,
          multiplicity: 'sep',
          shift: 3.9
        }],
        pyridine: [{
          proton: 'CH(2)',
          coupling: 0,
          multiplicity: 'm',
          shift: 8.58
        }, {
          proton: 'CH(3)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.35
        }, {
          proton: 'CH(4)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.76
        }],
        silicone_greasei: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 0.13
        }],
        tetrahydrofuran: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.79
        }, {
          proton: 'CH2O',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.63
        }],
        toluene: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.32
        }, {
          proton: 'CH(o/p)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.5
        }, {
          proton: 'CH(m)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.5
        }],
        triethylamine: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.96
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.45
        }]
      },
      dmso: {
        tms: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 0
        }],
        solvent: [{
          proton: 'X',
          coupling: 0,
          multiplicity: 'quint',
          shift: 2.5
        }],
        h2o: [{
          proton: 'H2O',
          coupling: 0,
          multiplicity: 's',
          shift: 3.33
        }],
        acetic_acid: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.91
        }],
        acetone: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.09
        }],
        acetonitrile: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.07
        }],
        benzene: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.37
        }],
        'tert-butyl_alcohol': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.11
        }, {
          proton: 'OHc',
          coupling: 0,
          multiplicity: 's',
          shift: 4.19
        }],
        'tert-butyl_methyl_ether': [{
          proton: 'CCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.11
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.08
        }],
        bhtb: [{
          proton: 'ArH',
          coupling: 0,
          multiplicity: 's',
          shift: 6.87
        }, {
          proton: 'OHc',
          coupling: 0,
          multiplicity: 's',
          shift: 6.65
        }, {
          proton: 'ArCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.18
        }, {
          proton: 'ArC(CH3)3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.36
        }],
        chloroform: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 8.32
        }],
        cyclohexane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 1.4
        }],
        '1,2-dichloroethane': [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.9
        }],
        dichloromethane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 5.76
        }],
        diethyl_ether: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.09
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.38
        }],
        diglyme: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.51
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.38
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.24
        }],
        '1,2-dimethoxyethane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.24
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.43
        }],
        dimethylacetamide: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.96
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.94
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.78
        }],
        dimethylformamide: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.95
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.89
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.73
        }],
        dimethyl_sulfoxide: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.54
        }],
        dioxane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.57
        }],
        ethanol: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.06
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.44
        }, {
          proton: 'OH',
          coupling: 5,
          multiplicity: 's,t',
          shift: 4.63
        }],
        ethyl_acetate: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.99
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 4.03
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.17
        }],
        ethyl_methyl_ketone: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.07
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.43
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.91
        }],
        ethylene_glycol: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.34
        }],
        'grease^f': [],
        'n-hexane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 't',
          shift: 0.86
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.25
        }],
        hmpag: [{
          proton: 'CH3',
          coupling: 9.5,
          multiplicity: 'd',
          shift: 2.53
        }],
        methanol: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.16
        }, {
          proton: 'OH',
          coupling: 0,
          multiplicity: 's',
          shift: 4.01
        }],
        nitromethane: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 4.42
        }],
        'n-pentane': [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.88
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.27
        }],
        '2-propanol': [{
          proton: 'CH3',
          coupling: 6,
          multiplicity: 'd',
          shift: 1.04
        }, {
          proton: 'CH',
          coupling: 6,
          multiplicity: 'sep',
          shift: 3.78
        }],
        pyridine: [{
          proton: 'CH(2)',
          coupling: 0,
          multiplicity: 'm',
          shift: 8.58
        }, {
          proton: 'CH(3)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.39
        }, {
          proton: 'CH(4)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.79
        }],
        silicone_greasei: [],
        tetrahydrofuran: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.76
        }, {
          proton: 'CH2O',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.6
        }],
        toluene: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.3
        }, {
          proton: 'CH(o/p)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.18
        }, {
          proton: 'CH(m)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.25
        }],
        triethylamine: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.93
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.43
        }]
      },
      c6d6: {
        tms: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 0
        }],
        solvent: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 7.16
        }],
        h2o: [{
          proton: 'H2O',
          coupling: 0,
          multiplicity: 's',
          shift: 0.4
        }],
        acetic_acid: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.55
        }],
        acetone: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.55
        }],
        acetonitrile: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.55
        }],
        benzene: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.15
        }],
        'tert-butyl_alcohol': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.05
        }, {
          proton: 'OHc',
          coupling: 0,
          multiplicity: 's',
          shift: 1.55
        }],
        'tert-butyl_methyl_ether': [{
          proton: 'CCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.07
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.04
        }],
        bhtb: [{
          proton: 'ArH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.05
        }, {
          proton: 'OHc',
          coupling: 0,
          multiplicity: 's',
          shift: 4.79
        }, {
          proton: 'ArCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.24
        }, {
          proton: 'ArC(CH3)3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.38
        }],
        chloroform: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 6.15
        }],
        cyclohexane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 1.4
        }],
        '1,2-dichloroethane': [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 2.9
        }],
        dichloromethane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 4.27
        }],
        diethyl_ether: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.11
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.26
        }],
        diglyme: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.46
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.34
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.11
        }],
        '1,2-dimethoxyethane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.12
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.33
        }],
        dimethylacetamide: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.6
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.57
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.05
        }],
        dimethylformamide: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.63
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.36
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.86
        }],
        dimethyl_sulfoxide: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.68
        }],
        dioxane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.35
        }],
        ethanol: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.96
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.34
        }],
        ethyl_acetate: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.65
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.89
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.92
        }],
        ethyl_methyl_ketone: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.58
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 1.81
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.85
        }],
        ethylene_glycol: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.41
        }],
        'grease^f': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 'm',
          shift: 0.92
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'br_s',
          shift: 1.36
        }],
        'n-hexane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 't',
          shift: 0.89
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.24
        }],
        hmpag: [{
          proton: 'CH3',
          coupling: 9.5,
          multiplicity: 'd',
          shift: 2.4
        }],
        methanol: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.07
        }],
        nitromethane: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.94
        }],
        'n-pentane': [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.86
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.23
        }],
        '2-propanol': [{
          proton: 'CH3',
          coupling: 6,
          multiplicity: 'd',
          shift: 0.95
        }, {
          proton: 'CH',
          coupling: 6,
          multiplicity: 'sep',
          shift: 3.67
        }],
        pyridine: [{
          proton: 'CH(2)',
          coupling: 0,
          multiplicity: 'm',
          shift: 8.53
        }, {
          proton: 'CH(3)',
          coupling: 0,
          multiplicity: 'm',
          shift: 6.66
        }, {
          proton: 'CH(4)',
          coupling: 0,
          multiplicity: 'm',
          shift: 6.98
        }],
        silicone_greasei: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 0.29
        }],
        tetrahydrofuran: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.4
        }, {
          proton: 'CH2O',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.57
        }],
        toluene: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.11
        }, {
          proton: 'CH(o/p)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.02
        }, {
          proton: 'CH(m)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.13
        }],
        triethylamine: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.96
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.4
        }]
      },
      cd3cn: {
        tms: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 0
        }],
        solvent: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 1.94
        }],
        h2o: [{
          proton: 'H2O',
          coupling: 0,
          multiplicity: 's',
          shift: 2.13
        }],
        acetic_acid: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.96
        }],
        acetone: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.08
        }],
        acetonitrile: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.96
        }],
        benzene: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.37
        }],
        'tert-butyl_alcohol': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.16
        }, {
          proton: 'OHc',
          coupling: 0,
          multiplicity: 's',
          shift: 2.18
        }],
        'tert-butyl_methyl_ether': [{
          proton: 'CCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.14
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.13
        }],
        bhtb: [{
          proton: 'ArH',
          coupling: 0,
          multiplicity: 's',
          shift: 6.97
        }, {
          proton: 'OHc',
          coupling: 0,
          multiplicity: 's',
          shift: 5.2
        }, {
          proton: 'ArCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.22
        }, {
          proton: 'ArC(CH3)3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.39
        }],
        chloroform: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.58
        }],
        cyclohexane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 1.44
        }],
        '1,2-dichloroethane': [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.81
        }],
        dichloromethane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 5.44
        }],
        diethyl_ether: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.12
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.42
        }],
        diglyme: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.53
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.45
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.29
        }],
        '1,2-dimethoxyethane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.28
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.45
        }],
        dimethylacetamide: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.97
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.96
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.83
        }],
        dimethylformamide: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.92
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.89
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.77
        }],
        dimethyl_sulfoxide: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.5
        }],
        dioxane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.6
        }],
        ethanol: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.12
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.54
        }, {
          proton: 'OH',
          coupling: 5,
          multiplicity: 's,t',
          shift: 2.47
        }],
        ethyl_acetate: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 1.97
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 4.06
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.2
        }],
        ethyl_methyl_ketone: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.06
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.43
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.96
        }],
        ethylene_glycol: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.51
        }],
        'grease^f': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 'm',
          shift: 0.86
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'br_s',
          shift: 1.27
        }],
        'n-hexane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 't',
          shift: 0.89
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.28
        }],
        hmpag: [{
          proton: 'CH3',
          coupling: 9.5,
          multiplicity: 'd',
          shift: 2.57
        }],
        methanol: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.28
        }, {
          proton: 'OH',
          coupling: 0,
          multiplicity: 's',
          shift: 2.16
        }],
        nitromethane: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 4.31
        }],
        'n-pentane': [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.87
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.29
        }],
        '2-propanol': [{
          proton: 'CH3',
          coupling: 6,
          multiplicity: 'd',
          shift: 1.09
        }, {
          proton: 'CH',
          coupling: 6,
          multiplicity: 'sep',
          shift: 3.87
        }],
        pyridine: [{
          proton: 'CH(2)',
          coupling: 0,
          multiplicity: 'm',
          shift: 8.57
        }, {
          proton: 'CH(3)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.33
        }, {
          proton: 'CH(4)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.73
        }],
        silicone_greasei: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 0.08
        }],
        tetrahydrofuran: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.8
        }, {
          proton: 'CH2O',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.64
        }],
        toluene: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.33
        }, {
          proton: 'CH(o/p)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.2
        }, {
          proton: 'CH(m)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.2
        }],
        triethylamine: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.96
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.45
        }]
      },
      cd3od: {
        tms: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 0
        }],
        solvent: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 3.31
        }],
        h2o: [{
          proton: 'H2O',
          coupling: 0,
          multiplicity: 's',
          shift: 4.87
        }],
        acetic_acid: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.99
        }],
        acetone: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.15
        }],
        acetonitrile: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.03
        }],
        benzene: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.33
        }],
        'tert-butyl_alcohol': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.4
        }],
        'tert-butyl_methyl_ether': [{
          proton: 'CCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.15
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.2
        }],
        bhtb: [{
          proton: 'ArH',
          coupling: 0,
          multiplicity: 's',
          shift: 6.92
        }, {
          proton: 'ArCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.21
        }, {
          proton: 'ArC(CH3)3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.4
        }],
        chloroform: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.9
        }],
        cyclohexane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 1.45
        }],
        '1,2-dichloroethane': [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.78
        }],
        dichloromethane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 5.49
        }],
        diethyl_ether: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.18
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.49
        }],
        diglyme: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.61
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.58
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.35
        }],
        '1,2-dimethoxyethane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.35
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.52
        }],
        dimethylacetamide: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.07
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.31
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.92
        }],
        dimethylformamide: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.97
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.99
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.86
        }],
        dimethyl_sulfoxide: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.65
        }],
        dioxane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.66
        }],
        ethanol: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.19
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.6
        }],
        ethyl_acetate: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.01
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 4.09
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.24
        }],
        ethyl_methyl_ketone: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.12
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.5
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.01
        }],
        ethylene_glycol: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.59
        }],
        'grease^f': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 'm',
          shift: 0.88
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'br_s',
          shift: 1.29
        }],
        'n-hexane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 't',
          shift: 0.9
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.29
        }],
        hmpag: [{
          proton: 'CH3',
          coupling: 9.5,
          multiplicity: 'd',
          shift: 2.64
        }],
        methanol: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.34
        }],
        nitromethane: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 4.34
        }],
        'n-pentane': [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.89
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.29
        }],
        '2-propanol': [{
          proton: 'CH3',
          coupling: 6,
          multiplicity: 'd',
          shift: 1.5
        }, {
          proton: 'CH',
          coupling: 6,
          multiplicity: 'sep',
          shift: 3.92
        }],
        pyridine: [{
          proton: 'CH(2)',
          coupling: 0,
          multiplicity: 'm',
          shift: 8.53
        }, {
          proton: 'CH(3)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.44
        }, {
          proton: 'CH(4)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.85
        }],
        silicone_greasei: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 0.1
        }],
        tetrahydrofuran: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.87
        }, {
          proton: 'CH2O',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.71
        }],
        toluene: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.32
        }, {
          proton: 'CH(o/p)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.16
        }, {
          proton: 'CH(m)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.16
        }],
        triethylamine: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.05
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.58
        }]
      },
      d2o: {
        tms: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 0
        }],
        solvent: [{
          proton: 'X',
          coupling: 0,
          multiplicity: '',
          shift: 4.79
        }],
        h2o: [],
        acetic_acid: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.08
        }],
        acetone: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.22
        }],
        acetonitrile: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.06
        }],
        benzene: [],
        'tert-butyl_alcohol': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.24
        }],
        'tert-butyl_methyl_ether': [{
          proton: 'CCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 1.21
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.22
        }],
        bhtb: [],
        chloroform: [],
        cyclohexane: [],
        '1,2-dichloroethane': [],
        dichloromethane: [],
        diethyl_ether: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.17
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.56
        }],
        diglyme: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.67
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.61
        }, {
          proton: 'OCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.37
        }],
        '1,2-dimethoxyethane': [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.37
        }, {
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.6
        }],
        dimethylacetamide: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.08
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.06
        }, {
          proton: 'NCH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.9
        }],
        dimethylformamide: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 7.92
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.01
        }, {
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.85
        }],
        dimethyl_sulfoxide: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 2.71
        }],
        dioxane: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 's',
          shift: 3.75
        }],
        ethanol: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.17
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.65
        }],
        ethyl_acetate: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.07
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 4.14
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.24
        }],
        ethyl_methyl_ketone: [{
          proton: 'CH3CO',
          coupling: 0,
          multiplicity: 's',
          shift: 2.19
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 'q',
          shift: 3.18
        }, {
          proton: 'CH2CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 1.26
        }],
        ethylene_glycol: [{
          proton: 'CH',
          coupling: 0,
          multiplicity: 's',
          shift: 3.65
        }],
        'grease^f': [],
        'n-hexane': [],
        hmpag: [{
          proton: 'CH3',
          coupling: 9.5,
          multiplicity: 'd',
          shift: 2.61
        }],
        methanol: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 3.34
        }],
        nitromethane: [{
          proton: 'CH3',
          coupling: 0,
          multiplicity: 's',
          shift: 4.4
        }],
        'n-pentane': [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.9
        }],
        '2-propanol': [{
          proton: 'CH3',
          coupling: 6,
          multiplicity: 'd',
          shift: 1.17
        }, {
          proton: 'CH',
          coupling: 6,
          multiplicity: 'sep',
          shift: 4.02
        }],
        pyridine: [{
          proton: 'CH(2)',
          coupling: 0,
          multiplicity: 'm',
          shift: 8.52
        }, {
          proton: 'CH(3)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.45
        }, {
          proton: 'CH(4)',
          coupling: 0,
          multiplicity: 'm',
          shift: 7.87
        }],
        silicone_greasei: [],
        tetrahydrofuran: [{
          proton: 'CH2',
          coupling: 0,
          multiplicity: 'm',
          shift: 1.88
        }, {
          proton: 'CH2O',
          coupling: 0,
          multiplicity: 'm',
          shift: 3.74
        }],
        toluene: [],
        triethylamine: [{
          proton: 'CH3',
          coupling: 7,
          multiplicity: 't',
          shift: 0.99
        }, {
          proton: 'CH2',
          coupling: 7,
          multiplicity: 'q',
          shift: 2.57
        }]
      }
    };

    const couplingPatterns = ['s', 'd', 't', 'q', 'quint', 'h', 'sept', 'o', 'n'];

    const toCheck = ['solvent', 'h2o', 'tms'];
    /**
     * Try to remove peaks of impurities.
     */

    function peaksFilterImpurities(peakList) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        solvent,
        error = 0.025,
        remove = false
      } = options;

      if (solvent) {
        if (solvent === '(cd3)2so') solvent = 'dmso';
        if (solvent === 'meod') solvent = 'cd3od';
        let solventImpurities = impurities[solvent];

        for (let impurity of toCheck) {
          let impurityShifts = solventImpurities[impurity];
          checkImpurity(peakList, impurityShifts, {
            error,
            remove,
            name: impurity
          });
        }
      }

      return peakList;
    }

    function checkImpurity(peakList, impurity, options) {
      let {
        name,
        error,
        remove
      } = options;
      let j, tolerance, difference;
      let i = impurity.length;

      while (i--) {
        j = peakList.length;

        while (j--) {
          tolerance = error + peakList[j].width;
          difference = Math.abs(impurity[i].shift - peakList[j].x);

          if (difference < tolerance) {
            // && (impurity[i].multiplicity === '' || (impurity[i].multiplicity.indexOf(peakList[j].multiplicity)) { // some impurities has multiplicities like 'bs' but at presents it is unsupported
            if (remove) {
              peakList.splice(j, 1);
            } else {
              peakList[j].kind = name;
            }
          }
        }
      }
    }

    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 {
      constructor() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        const {
          fwhm = 500,
          sd
        } = options;
        this.fwhm = sd ? gaussianWidthToFWHM(2 * sd) : fwhm;
      }

      fwhmToWidth() {
        let fwhm = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.fwhm;
        return gaussianFwhmToWidth(fwhm);
      }

      widthToFWHM(width) {
        return gaussianWidthToFWHM(width);
      }

      fct(x) {
        return gaussianFct(x, this.fwhm);
      }

      getArea() {
        let height = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : calculateGaussianHeight({
          fwhm: this.fwhm
        });
        return getGaussianArea({
          fwhm: this.fwhm,
          height
        });
      }

      getFactor(area) {
        return getGaussianFactor(area);
      }

      getData() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        return getGaussianData(this, options);
      }

      calculateHeight() {
        let area = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        return calculateGaussianHeight({
          fwhm: this.fwhm,
          area
        });
      }

      getParameters() {
        return ['fwhm'];
      }

    }
    function calculateGaussianHeight(options) {
      let {
        fwhm = 500,
        area = 1,
        sd
      } = options;
      if (sd) fwhm = gaussianWidthToFWHM(2 * sd);
      return 2 * area / ROOT_PI_OVER_LN2 / fwhm;
    }
    /**
     * Calculate the height of the gaussian function of a specific width (fwhm) at a speicifc
     * x position (the gaussian is centered on x=0)
     * @param x
     * @param fwhm
     * @returns y
     */

    function gaussianFct(x, fwhm) {
      return Math.exp(GAUSSIAN_EXP_FACTOR * Math.pow(x / fwhm, 2));
    }
    function gaussianWidthToFWHM(width) {
      return width * ROOT_2LN2;
    }
    function gaussianFwhmToWidth(fwhm) {
      return fwhm / ROOT_2LN2;
    }
    function getGaussianArea(options) {
      let {
        fwhm = 500,
        sd,
        height = 1
      } = options;
      if (sd) fwhm = gaussianWidthToFWHM(2 * sd);
      return height * ROOT_PI_OVER_LN2 * fwhm / 2;
    }
    function getGaussianFactor() {
      let area = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.9999;
      return Math.sqrt(2) * erfinv(area);
    }
    function getGaussianData() {
      let shape = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        fwhm = 500,
        sd
      } = shape;
      if (sd) fwhm = gaussianWidthToFWHM(2 * sd);
      let {
        length,
        factor = getGaussianFactor(),
        height = calculateGaussianHeight({
          fwhm
        })
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(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] = gaussianFct(i - center, fwhm) * height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }

    class Lorentzian {
      constructor() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        const {
          fwhm = 500
        } = options;
        this.fwhm = fwhm;
      }

      fwhmToWidth() {
        let fwhm = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.fwhm;
        return lorentzianFwhmToWidth(fwhm);
      }

      widthToFWHM(width) {
        return lorentzianWidthToFWHM(width);
      }

      fct(x) {
        return lorentzianFct(x, this.fwhm);
      }

      getArea() {
        let height = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        return getLorentzianArea({
          fwhm: this.fwhm,
          height
        });
      }

      getFactor(area) {
        return getLorentzianFactor(area);
      }

      getData() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        return getLorentzianData(this, options);
      }

      calculateHeight() {
        let area = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        return calculateLorentzianHeight({
          fwhm: this.fwhm,
          area
        });
      }

      getParameters() {
        return ['fwhm'];
      }

    }
    const calculateLorentzianHeight = _ref => {
      let {
        fwhm = 1,
        area = 1
      } = _ref;
      return 2 * area / Math.PI / fwhm;
    };
    const getLorentzianArea = options => {
      const {
        fwhm = 500,
        height = 1
      } = options;
      return height * Math.PI * fwhm / 2;
    };
    const lorentzianFct = (x, fwhm) => {
      return fwhm ** 2 / (4 * x ** 2 + fwhm ** 2);
    };
    const lorentzianWidthToFWHM = width => {
      return width * ROOT_THREE;
    };
    const lorentzianFwhmToWidth = fwhm => {
      return fwhm / ROOT_THREE;
    };
    const getLorentzianFactor = function () {
      let area = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.9999;

      if (area >= 1) {
        throw new Error('area should be (0 - 1)');
      }

      const halfResidual = (1 - area) * 0.5;

      const quantileFunction = p => Math.tan(Math.PI * (p - 0.5));

      return (quantileFunction(1 - halfResidual) - quantileFunction(halfResidual)) / 2;
    };
    const getLorentzianData = function () {
      let shape = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        fwhm = 500
      } = shape;
      let {
        length,
        factor = getLorentzianFactor(),
        height = calculateLorentzianHeight({
          fwhm,
          area: 1
        })
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(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] = lorentzianFct(i - center, fwhm) * height;
        data[length - 1 - i] = data[i];
      }

      return data;
    };

    class PseudoVoigt {
      constructor() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        const {
          fwhm = 500,
          mu = 0.5
        } = options;
        this.mu = mu;
        this.fwhm = fwhm;
      }

      fwhmToWidth() {
        let fwhm = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.fwhm;
        let mu = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.mu;
        return pseudoVoigtFwhmToWidth(fwhm, mu);
      }

      widthToFWHM(width) {
        let mu = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.mu;
        return pseudoVoigtWidthToFWHM(width, mu);
      }

      fct(x) {
        return pseudoVoigtFct(x, this.fwhm, this.mu);
      }

      getArea() {
        let height = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        return getPseudoVoigtArea({
          fwhm: this.fwhm,
          height,
          mu: this.mu
        });
      }

      getFactor(area) {
        return getPseudoVoigtFactor(area);
      }

      getData() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        const {
          length,
          factor,
          height = calculatePseudoVoigtHeight({
            fwhm: this.fwhm,
            mu: this.mu,
            area: 1
          })
        } = options;
        return getPseudoVoigtData(this, {
          factor,
          length,
          height
        });
      }

      calculateHeight() {
        let area = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        return calculatePseudoVoigtHeight({
          fwhm: this.fwhm,
          mu: this.mu,
          area
        });
      }

      getParameters() {
        return ['fwhm', 'mu'];
      }

    }
    const calculatePseudoVoigtHeight = function () {
      let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let {
        fwhm = 1,
        mu = 0.5,
        area = 1
      } = options;
      return 2 * area / (fwhm * (mu * ROOT_PI_OVER_LN2 + (1 - mu) * Math.PI));
    };
    const pseudoVoigtFct = (x, fwhm, mu) => {
      return (1 - mu) * lorentzianFct(x, fwhm) + mu * gaussianFct(x, fwhm);
    };
    const pseudoVoigtWidthToFWHM = function (width) {
      let mu = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.5;
      return width * (mu * ROOT_2LN2_MINUS_ONE + 1);
    };
    const pseudoVoigtFwhmToWidth = function (fwhm) {
      let mu = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.5;
      return fwhm / (mu * ROOT_2LN2_MINUS_ONE + 1);
    };
    const getPseudoVoigtArea = options => {
      const {
        fwhm = 500,
        height = 1,
        mu = 0.5
      } = options;
      return fwhm * height * (mu * ROOT_PI_OVER_LN2 + (1 - mu) * Math.PI) / 2;
    };
    const getPseudoVoigtFactor = function () {
      let area = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.9999;
      let mu = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.5;
      return mu < 1 ? getLorentzianFactor(area) : getGaussianFactor(area);
    };
    const getPseudoVoigtData = function () {
      let shape = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        fwhm = 500,
        mu = 0.5
      } = shape;
      let {
        length,
        factor = getPseudoVoigtFactor(0.999, mu),
        height = calculatePseudoVoigtHeight({
          fwhm,
          mu,
          area: 1
        })
      } = options;

      if (!height) {
        height = 1 / (mu / Math.sqrt(-GAUSSIAN_EXP_FACTOR / Math.PI) * fwhm + (1 - mu) * fwhm * Math.PI / 2);
      }

      if (!length) {
        length = Math.min(Math.ceil(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] = pseudoVoigtFct(i - center, fwhm, mu) * height;
        data[length - 1 - i] = data[i];
      }

      return data;
    };

    class Gaussian2D {
      constructor() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        let {
          fwhm = 20,
          sd
        } = options;
        fwhm = ensureFWHM2D(fwhm, sd);
        this.fwhmX = fwhm.x;
        this.fwhmY = fwhm.y;
      }

      fct(x, y) {
        return gaussian2DFct(x, y, this.fwhmX, this.fwhmY);
      }

      getData() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        return getGaussian2DData({
          fwhm: {
            x: this.fwhmX,
            y: this.fwhmY
          }
        }, options);
      }

      getFactor() {
        let volume = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        return getGaussianFactor(volume);
      }

      getVolume() {
        let height = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : calculateGaussian2DHeight({
          fwhm: {
            x: this.fwhmX,
            y: this.fwhmY
          },
          volume: 1
        });
        return getGaussian2DVolume({
          fwhm: {
            x: this.fwhmX,
            y: this.fwhmY
          },
          height
        });
      }

      widthToFWHM(width) {
        return gaussianWidthToFWHM(width);
      }

      fwhmToWidth(fwhm) {
        return gaussianFwhmToWidth(fwhm);
      }

      calculateHeight() {
        let volume = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        return calculateGaussian2DHeight({
          volume,
          fwhm: {
            x: this.fwhmX,
            y: this.fwhmY
          }
        });
      }

      set fwhm(fwhm) {
        fwhm = ensureXYNumber$2(fwhm);
        this.fwhmX = fwhm.x;
        this.fwhmY = fwhm.y;
      }

    }
    const gaussian2DFct = (x, y, xFWHM, yFWHM) => {
      return Math.exp(GAUSSIAN_EXP_FACTOR * (Math.pow(x / xFWHM, 2) + Math.pow(y / yFWHM, 2)));
    };
    const getGaussian2DData = function (shape) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        fwhm = 50,
        sd
      } = shape;
      fwhm = ensureFWHM2D(fwhm, sd);
      let {
        factor = getGaussianFactor(),
        length = {
          x: 0,
          y: 0
        },
        height = calculateGaussian2DHeight({
          fwhm,
          volume: 1
        })
      } = options;
      factor = ensureXYNumber$2(factor);
      length = ensureXYNumber$2(length);

      for (const axis of ['x', 'y']) {
        if (!length[axis]) {
          length[axis] = Math.min(Math.ceil(fwhm[axis] * factor[axis]), Math.pow(2, 25) - 1);
          if (length[axis] % 2 === 0) length[axis]++;
        }
      }

      const xCenter = (length.x - 1) / 2;
      const yCenter = (length.y - 1) / 2;
      const data = new Array(length.x);

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

      for (let i = 0; i < length.x; i++) {
        for (let j = 0; j < length.y; j++) {
          data[i][j] = gaussian2DFct(i - xCenter, j - yCenter, fwhm.x, fwhm.y) * height;
        }
      }

      return data;
    };
    const calculateGaussian2DHeight = function () {
      let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let {
        volume = 1,
        fwhm = 50,
        sd
      } = options;
      fwhm = ensureFWHM2D(fwhm, sd);
      return volume * Math.LN2 * 4 / (Math.PI * fwhm.y * fwhm.x);
    };
    const getGaussian2DVolume = function () {
      let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let {
        fwhm = 50,
        height = 1,
        sd
      } = options;
      fwhm = ensureFWHM2D(fwhm, sd);
      return height * Math.PI * fwhm.y * fwhm.x / Math.LN2 / 4;
    };

    function ensureXYNumber$2(input) {
      return typeof input !== 'object' ? {
        x: input,
        y: input
      } : { ...input
      };
    }

    function ensureFWHM2D(fwhm, sd) {
      if (sd !== undefined) {
        let sdObject = ensureXYNumber$2(sd);
        return {
          x: gaussianWidthToFWHM(2 * sdObject.x),
          y: gaussianWidthToFWHM(2 * sdObject.y)
        };
      } else if (fwhm !== undefined) {
        return ensureXYNumber$2(fwhm);
      } else {
        throw new Error('ensureFWHM2D must have either fwhm or sd defined');
      }
    }

    /**
     * Generate a instance of a specific kind of shape.
     */

    function getShape1D(shape) {
      const {
        kind
      } = shape;

      switch (kind) {
        case 'gaussian':
          return new Gaussian(shape);

        case 'lorentzian':
          return new Lorentzian(shape);

        case 'pseudoVoigt':
          return new PseudoVoigt(shape);

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

    /**
     * Generate a instance of a specific kind of shape.
     */

    function getShape2D(shape) {
      const {
        kind
      } = shape;

      switch (kind) {
        case 'gaussian':
          return new Gaussian2D(shape);

        default:
          {
            const unHandled = kind; // eslint-disable-next-line @typescript-eslint/restrict-template-expressions

            throw Error(`Unknown distribution ${unHandled}`);
          }
      }
    }

    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 commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

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

    var d3Array = {exports: {}};

    (function (module, exports) {
      (function (global, factory) {
        factory(exports) ;
      })(commonjsGlobal, 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;
      });
    })(d3Array, d3Array.exports);

    const {
      bisectRight
    } = d3Array.exports;

    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) {
        let lambda = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 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() {
        let step = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 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() {
        let step = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 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) {
        let domain = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 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;
    var SplineInterpolator$1 = splineInterpolator;

    /**
     * Create an array with numbers between "from" and "to" of length "length"
     *
     * @param options - options
     * @return - array of distributed numbers between "from" and "to"
     */
    function createFromToArray() {
      let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let {
        from = 0,
        to = 1,
        length = 1000,
        includeFrom = true,
        includeTo = true,
        distribution = 'uniform'
      } = options;
      const array = new Float64Array(length);
      let div = length;

      if (includeFrom && includeTo) {
        div = length - 1;
      } else if (!includeFrom && includeTo || includeFrom && !includeTo) {
        div = length;
      } else if (!includeFrom && !includeTo) {
        div = length + 1;
      }

      let delta = (to - from) / div;

      if (distribution === 'uniform') {
        if (includeFrom) {
          let index = 0;

          while (index < length) {
            array[index] = from + delta * index;
            index++;
          }
        } else {
          let index = 0;

          while (index < length) {
            array[index] = from + delta * (index + 1);
            index++;
          }
        }
      } else if (distribution === 'log') {
        let base = (to / from) ** (1 / div);
        let firstExponent = Math.log(from) / Math.log(base);

        if (includeFrom) {
          let index = 0;

          while (index < length) {
            array[index] = base ** (firstExponent + index);
            index++;
          }
        } else {
          let index = 0;

          while (index < length) {
            array[index] = base ** (firstExponent + index + 1);
            index++;
          }
        }
      } else {
        throw new Error('Please choose for the distribution either uniform or log. By default the distribution chosen is uniform.');
      }

      return array;
    }

    /* eslint-disable @typescript-eslint/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];
    /**
     * Polyval.
     *
     * @param c - Array of Number.
     * @param x - Number.
     * @returns Number.
     */

    function polyval(c, x) {
      let p = 0;

      for (const coef of c) {
        p = p * x + coef;
      }

      return p;
    }
    /**
     * Calculates a rational approximation.
     *
     * @private
     * @param x - Number.
     * @param v - Number.
     * @param P - Array of polynomial coefficients.
     * @param Q - Array of polynomial coefficients.
     * @param Y - Number.
     * @returns Rational approximation.
     */


    function calc(x, v, P, Q, Y) {
      const s = x - v;
      const r = polyval(P, s) / polyval(Q, s);
      return Y * x + r * x;
    }
    /**
     * Evaluates the complementary inverse error function for an input value.
     *
     * @private
     * @param x - Input value.
     * @returns Evaluated complementary inverse error function.
     */


    function erfcinv(x) {
      let sign = false;
      let val;
      let q;
      let g;
      let r; // [1] Special cases...
      // NaN:

      if (Number.isNaN(x)) {
        return 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.
    }

    /**
     * RayleighCdf.
     *
     * @param x - data
     * @param sigma - standard deviation
     * @returns - rayleigh cdf
     */
    function rayleighCdf(x) {
      let sigma = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;

      if (x < 0) {
        return 0;
      }

      return -Math.expm1(-Math.pow(x, 2) / (2 * Math.pow(sigma, 2)));
    }

    /**
     * Determine noise level by san plot methodology (https://doi.org/10.1002/mrc.4882)
     *
     * @param array - real or magnitude spectra data.
     * @param options - options
     * @returns noise level
     */

    function xNoiseSanPlot(array) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        mask,
        cutOff,
        refine = true,
        magnitudeMode = false,
        scaleFactor = 1,
        factorStd = 5,
        fixOffset = true
      } = options;
      let input;

      if (Array.isArray(mask) && mask.length === array.length) {
        input = new Float64Array(array.filter((_e, i) => !mask[i]));
      } else {
        input = new Float64Array(array);
      }

      if (scaleFactor > 1) {
        for (let i = 0; i < input.length; i++) {
          input[i] *= scaleFactor;
        }
      }

      input = input.sort().reverse();

      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[input.length - 1] >= 0 ? input.length : input.findIndex(e => e < 0);
      let lastPositiveValueIndex = firstNegativeValueIndex - 1;

      for (let i = lastPositiveValueIndex; i >= 0; i--) {
        if (input[i] > 0) {
          lastPositiveValueIndex = i;
          break;
        }
      }

      let signPositive = input.slice(0, lastPositiveValueIndex + 1);
      let signNegative = 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,
        sanplot: generateSanPlot(input, {
          fromTo: {
            positive: {
              from: 0,
              to: lastPositiveValueIndex
            },
            negative: {
              from: firstNegativeValueIndex,
              to: input.length
            }
          }
        })
      };
    }
    /**
     * DetermineCutOff.
     *
     * @param signPositive - Array of numbers.
     * @param [options = {}] - Options.
     * @param [options.mask] - Boolean array to filter data, if the i-th element is true then the i-th element of the distribution will be ignored.
     * @param [options.scaleFactor=1] - Factor to scale the data input[i]*=scaleFactor.
     * @param [options.cutOff] - Percent of positive signal distribution where the noise level will be determined, if it is not defined the program calculate it.
     * @param [options.factorStd=5] - Factor times std to determine what will be marked as signals.
     * @param [options.refine=true] - If true the noise level will be recalculated get out the signals using factorStd.
     * @param [options.fixOffset=true] - If the baseline is correct, the midpoint of distribution should be zero. If true, the distribution will be centered.
     * @param [options.logBaseY=2] - Log scale to apply in the intensity axis in order to avoid big numbers.
     * @param options.magnitudeMode -
     * @param options.considerList -
     * @param options.considerList.from -
     * @param options.considerList.step -
     * @param options.considerList.to -
     * @param options.fromTo -
     * @returns Result.
     */

    function determineCutOff(signPositive) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      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;
        elementsOfCutOff.forEach(element => {
          kiSqrt += Math.pow(element[1] - averageValue, 2);
        });

        if (kiSqrt < minKi) {
          minKi = kiSqrt;
          whereToCutStat = i;
        }
      }

      return whereToCutStat;
    }
    /**
     * SimpleNormInvs.
     *
     * @param data - Data array.
     * @param [options = {}] - Options.
     * @param [options.mask] - Boolean array to filter data, if the i-th element is true then the i-th element of the distribution will be ignored.
     * @param [options.scaleFactor=1] - Factor to scale the data input[i]*=scaleFactor.
     * @param [options.cutOff] - Percent of positive signal distribution where the noise level will be determined, if it is not defined the program calculate it.
     * @param [options.factorStd=5] - Factor times std to determine what will be marked as signals.
     * @param [options.refine=true] - If true the noise level will be recalculated get out the signals using factorStd.
     * @param [options.fixOffset=true] - If the baseline is correct, the midpoint of distribution should be zero. If true, the distribution will be centered.
     * @param [options.logBaseY=2] - Log scale to apply in the intensity axis in order to avoid big numbers.
     * @param options.magnitudeMode -
     * @param options.considerList -
     * @param options.considerList.from -
     * @param options.considerList.step -
     * @param options.considerList.to -
     * @param options.fromTo -
     * @returns Result.
     */


    function simpleNormInv(data) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        magnitudeMode = false
      } = options;
      if (!Array.isArray(data)) data = [data];
      let from = 0;
      let to = 2;
      let step = 0.01;
      let xTraining = Array.from(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$1(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;
    }
    /**
     * CreateArray.
     *
     * @param from - From.
     * @param to - To.
     * @param step - Step.
     * @returns Array of results.
     */


    function createArray(from, to, step) {
      // Changed Array to Float64Array
      let result = new Float64Array(Math.abs((from - to) / step + 1));

      for (let i = 0; i < result.length; i++) {
        result[i] = from + i * step;
      }

      return result;
    }
    /**
     * GenerateSanPlot.
     *
     * @param array - Array.
     * @param [options = {}] - Options.
     * @param [options.mask] - Boolean array to filter data, if the i-th element is true then the i-th element of the distribution will be ignored.
     * @param [options.scaleFactor=1] - Factor to scale the data input[i]*=scaleFactor.
     * @param [options.cutOff] - Percent of positive signal distribution where the noise level will be determined, if it is not defined the program calculate it.
     * @param [options.factorStd=5] - Factor times std to determine what will be marked as signals.
     * @param [options.refine=true] - If true the noise level will be recalculated get out the signals using factorStd.
     * @param [options.fixOffset=true] - If the baseline is correct, the midpoint of distribution should be zero. If true, the distribution will be centered.
     * @param [options.logBaseY=2] - Log scale to apply in the intensity axis in order to avoid big numbers.
     * @param options.magnitudeMode -
     * @param options.considerList -
     * @param options.considerList.from -
     * @param options.considerList.step -
     * @param options.considerList.to -
     * @param options.fromTo -
     * @returns Results.
     */


    function generateSanPlot(array) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        fromTo,
        logBaseY = 2
      } = options;
      let sanplot = {};

      for (let key in fromTo) {
        let {
          from,
          to
        } = fromTo[key];
        sanplot[key] = from !== to ? scale(array.slice(from, to), {
          logBaseY
        }) : {
          x: [],
          y: []
        };

        if (key === 'negative') {
          sanplot[key].y.reverse();
        }
      }

      return sanplot;
    }
    /**
     * Scale.
     *
     * @param array - Array.
     * @param [options = {}] - Options.
     * @param [options.mask] - Boolean array to filter data, if the i-th element is true then the i-th element of the distribution will be ignored.
     * @param [options.scaleFactor=1] - Factor to scale the data input[i]*=scaleFactor.
     * @param [options.cutOff] - Percent of positive signal distribution where the noise level will be determined, if it is not defined the program calculate it.
     * @param [options.factorStd=5] - Factor times std to determine what will be marked as signals.
     * @param [options.refine=true] - If true the noise level will be recalculated get out the signals using factorStd.
     * @param [options.fixOffset=true] - If the baseline is correct, the midpoint of distribution should be zero. If true, the distribution will be centered.
     * @param [options.logBaseY=2] - Log scale to apply in the intensity axis in order to avoid big numbers.
     * @param options.magnitudeMode -
     * @param options.considerList -
     * @param options.considerList.from -
     * @param options.considerList.step -
     * @param options.considerList.to -
     * @param options.fromTo -
     * @returns Results.
     */


    function scale(array) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        log10,
        abs
      } = Math;
      const {
        logBaseY
      } = options;

      if (logBaseY) {
        array = array.slice();
        const logOfBase = log10(logBaseY);

        for (let i = 0; i < array.length; i++) {
          array[i] = log10(abs(array[i])) / logOfBase;
        }
      }

      const xAxis = createFromToArray({
        from: 0,
        to: array.length - 1,
        length: array.length
      });
      return {
        x: xAxis,
        y: array
      };
    }

    /**
     * This function returns an array with absolute values
     *
     * @param array - array of data
     * @returns - array with absolute values
     */
    function xAbsolute(array) {
      let tmpArray = array.slice();

      for (let i = 0; i < tmpArray.length; i++) {
        if (tmpArray[i] < 0) tmpArray[i] *= -1;
      }

      return tmpArray;
    }

    const toString$2 = Object.prototype.toString;
    /**
     * Checks if an object is an instance of an Array (array or typed array).
     *
     * @param {any} value - Object to check.
     * @returns {boolean} True if the object is an array.
     */

    function isAnyArray(value) {
      return toString$2.call(value).endsWith('Array]');
    }

    var medianQuickselect_min = {exports: {}};

    (function (module) {
      (function () {
        function a(d) {
          for (var e = 0, f = d.length - 1, g = void 0, h = void 0, i = void 0, j = c(e, f); !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;
      })();
    })(medianQuickselect_min);

    var quickSelectMedian = medianQuickselect_min.exports;

    /**
     * Calculates the median of an array
     *
     * @param input - Array containing values
     * @returns - median
     */

    function xMedian(input) {
      if (!isAnyArray(input)) {
        throw new TypeError('input must be an array');
      }

      if (input.length === 0) {
        throw new TypeError('input must not be empty');
      } // we need to slice because the order of elements is changed in the quickselect
      // https://github.com/mad-gooze/median-quickselect


      return quickSelectMedian(input.slice());
    }

    /**
     * This function calculates the median after taking the reimAbsolute values of the points
     *
     * @param array - the array for which we want to calculate the absolute value
     * @returns - median
     */

    function xAbsoluteMedian(array) {
      return xMedian(xAbsolute(array));
    }

    /**
     * This function xAdd the first array by the second array or a constant value to each element of the first array
     *
     * @param array1 - the first array
     * @param array2 - the second array or number
     */

    function xAdd(array1, array2) {
      let isConstant = false;
      let constant = 0;

      if (isAnyArray(array2)) {
        if (array1.length !== array2.length) {
          throw new Error('xAdd: size of array1 and array2 must be identical');
        }
      } else {
        isConstant = true;
        constant = 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;
    }

    /**
     * Checks if input is of type array
     *
     * @param input - input
     */

    function xCheck(input) {
      if (!isAnyArray(input)) {
        throw new TypeError('input must be an array');
      }

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

    /**
     * Returns the closest index of a `target`
     *
     * @param array - array of numbers
     * @param target - target
     * @returns - closest index
     */
    function xFindClosestIndex(array, target) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      const {
        sorted = true
      } = options;

      if (sorted) {
        let low = 0;
        let high = array.length - 1;
        let middle = 0;

        while (high - low > 1) {
          middle = low + (high - low >> 1);

          if (array[middle] < target) {
            low = middle;
          } else if (array[middle] > target) {
            high = middle;
          } else {
            return middle;
          }
        }

        if (low < array.length - 1) {
          if (Math.abs(target - array[low]) < Math.abs(array[low + 1] - target)) {
            return low;
          } else {
            return low + 1;
          }
        } else {
          return low;
        }
      } else {
        let index = 0;
        let diff = Number.POSITIVE_INFINITY;

        for (let i = 0; i < array.length; i++) {
          const currentDiff = Math.abs(array[i] - target);

          if (currentDiff < diff) {
            diff = currentDiff;
            index = i;
          }
        }

        return index;
      }
    }

    /**
     * Returns an object with {fromIndex, toIndex} for a specific from / to
     *
     * @param x - array of numbers
     * @param options - Options
     */

    function xGetFromToIndex(x) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        fromIndex,
        toIndex,
        from,
        to
      } = options;

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

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

      if (fromIndex < 0) fromIndex = 0;
      if (toIndex < 0) toIndex = 0;
      if (fromIndex >= x.length) fromIndex = x.length - 1;
      if (toIndex >= x.length) toIndex = x.length - 1;
      if (fromIndex > toIndex) [fromIndex, toIndex] = [toIndex, fromIndex];
      return {
        fromIndex,
        toIndex
      };
    }

    /**
     * Computes the maximal value of an array of values
     *
     * @param array - array of numbers
     * @param options - options
     */

    function xMaxValue(array) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      xCheck(array);
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(array, options);
      let maxValue = array[fromIndex];

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

      return maxValue;
    }

    /**
     * Computes the minimal value of an array of values
     *
     * @param array - array of numbers
     * @param options - options
     */

    function xMinValue(array) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      xCheck(array);
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(array, options);
      let minValue = array[fromIndex];

      for (let i = fromIndex + 1; i <= toIndex; i++) {
        if (array[i] < minValue) {
          minValue = array[i];
        }
      }

      return minValue;
    }

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

      for (let i = 0; i < array.length - 1; ++i) {
        let absoluteDifference = array[i + 1] - array[i];

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

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

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

    /**
     * Returns true if x is monotone
     *
     * @param array - array of numbers
     */
    function xIsMonotoneIncreasing(array) {
      if (array.length < 2) {
        return true;
      }

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

      return true;
    }

    /**
     * This function calculates the median absolute deviation (MAD)
     * https://en.wikipedia.org/wiki/Median_absolute_deviation
     * @param array
     */

    function xMedianAbsoluteDeviation(array) {
      const median = xMedian(array);
      const averageDeviations = new Float64Array(array.length);

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

      return {
        median,
        mad: xMedian(averageDeviations)
      };
    }

    /**
     * Return min and max values of an array
     *
     * @param array - array of number
     * @returns - Object with 2 properties, min and max
     */

    function xMinMaxValues(array) {
      xCheck(array);
      let min = array[0];
      let max = array[0];

      for (let value of array) {
        if (value < min) min = value;
        if (value > max) max = value;
      }

      return {
        min,
        max
      };
    }

    /**
     * Determine noise level using MAD https://en.wikipedia.org/wiki/Median_absolute_deviation
     * Constant to convert mad to sd calculated using https://www.wolframalpha.com/input?i=sqrt%282%29+inverse+erf%280.5%29
     * This assumes a gaussian distribution of the noise
     * @param array
     * @returns noise level corresponding to one standard deviation
     */

    function xNoiseStandardDeviation(array) {
      const {
        mad,
        median
      } = xMedianAbsoluteDeviation(array);
      return {
        sd: mad / 0.6744897501960817,
        mad,
        median
      };
    }

    /**
     * This function calculate the norm of a vector
     *
     * @example xNorm([3, 4]) -> 5
     * @param array - array
     * @returns - calculated norm
     */
    function xNorm(array) {
      let result = 0;
      array.forEach(element => {
        result += element ** 2;
      });
      return Math.sqrt(result);
    }

    /** Fill an array with sequential numbers
     *
     * @param input - optional destination array (if not provided a new array will be created)
     * @param options - options
     * @return array with sequential numbers
     */

    function xSequentialFill() {
      let input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      if (typeof input === 'object' && !isAnyArray(input)) {
        options = input;
        input = [];
      }

      if (!isAnyArray(input)) {
        throw new TypeError('input must be an array');
      } // maybe should not specify default step and size


      let {
        from = 0,
        to = 10,
        size = Array.isArray(input) || input.constructor === Float64Array || input.constructor === Uint16Array ? input.length : 0,
        step = null
      } = options;

      if (!size) {
        if (step) {
          size = Math.floor((to - from) / step) + 1;
        } else {
          size = to - from + 1;
        }
      }

      if (!step && size) {
        step = (to - from) / (size - 1);
      }

      if (Array.isArray(input)) {
        // only works with normal array
        input.length = 0;

        for (let i = 0; i < size; i++) {
          input.push(from);
          if (step) from += step;
        }
      } else {
        if (Array.isArray(input) || input.constructor === Float64Array || input.constructor === Uint16Array && input.length !== size) {
          throw new Error('sequentialFill typed array must have the correct length');
        }

        for (let i = 0; i < size; i++) {
          if (Array.isArray(input) || input.constructor === Float64Array || input.constructor === Uint16Array) {
            input[i] = from;
          }

          if (step) {
            from += step;
          }
        }
      }

      return Array.isArray(input) || input.constructor === Float64Array || input.constructor === Uint16Array ? Array.from(input) : [];
    }

    /**
     * Throw an error in no an object of x,y arrays
     *
     * @param data - array of points {x,y,z}
     */

    function xyCheck(data) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        minLength
      } = options;

      if (typeof data !== 'object' || !isAnyArray(data.x) || !isAnyArray(data.y)) {
        throw new Error('Data must be an object of x and y arrays');
      }

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

      if (minLength) {
        if (data.x.length < minLength) {
          throw new Error(`data.x must have a length of at least ${minLength}`);
        }
      }
    }

    /**
     * Finds the closest point
     *
     * @param data - x array should be sorted and ascending
     * @param target - target to search
     * @returns - closest point
     */

    function xyFindClosestPoint(
    /** points */
    data, target) {
      const {
        x,
        y
      } = data;
      const index = xFindClosestIndex(x, target);
      return {
        x: x[index],
        y: y[index]
      };
    }

    /**
     * Normalize an array of zones:
     * - ensure than from < to
     * - merge overlapping zones
     * - deal with exclusions zones
     * - if no zones is specified add one between -Infinity and +Infinity
     * @param zones - array of zones
     * @param options - options
     * @returns array of zones
     */
    function zonesNormalize() {
      let zones = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        from = Number.NEGATIVE_INFINITY,
        to = Number.POSITIVE_INFINITY,
        exclusions = []
      } = options;
      if (from > to) [from, to] = [to, from];
      zones = JSON.parse(JSON.stringify(zones)).map(zone => zone.from > zone.to ? {
        from: zone.to,
        to: zone.from
      } : zone);
      zones = zones.sort((a, b) => {
        if (a.from !== b.from) return a.from - b.from;
        return a.to - b.to;
      });

      if (zones.length === 0) {
        zones.push({
          from,
          to
        });
      }

      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 beforeExclusionsZones = [currentZone];

      for (let i = 1; i < zones.length; i++) {
        let zone = zones[i];

        if (zone.from <= currentZone.to) {
          if (currentZone.to < zone.to) {
            currentZone.to = zone.to;
          }
        } else {
          currentZone = zone;
          beforeExclusionsZones.push(currentZone);
        }
      }

      if (exclusions.length === 0) return beforeExclusionsZones;
      const normalizedExclusions = zonesNormalize(exclusions);
      let currentExclusionIndex = 0;
      const results = [];
      let counter = 0;

      for (let zoneIndex = 0; zoneIndex < beforeExclusionsZones.length; zoneIndex++) {
        if (counter++ > 5) break;
        const zone = beforeExclusionsZones[zoneIndex];

        if (currentExclusionIndex === normalizedExclusions.length) {
          // we analysed all the exclusion zones
          results.push(zone);
          continue;
        }

        while (currentExclusionIndex < normalizedExclusions.length && normalizedExclusions[currentExclusionIndex].to <= zone.from) {
          currentExclusionIndex++;
        }

        if (currentExclusionIndex === normalizedExclusions.length) {
          // we analysed all the exclusion zones
          results.push(zone);
          continue;
        }

        if (zone.to < normalizedExclusions[currentExclusionIndex].from) {
          // no problems, not yet in exclusion
          results.push(zone);
          continue;
        }

        if (normalizedExclusions[currentExclusionIndex].to >= zone.to) {
          // could be totally excluded
          if (normalizedExclusions[currentExclusionIndex].from <= zone.from) {
            continue;
          }

          results.push({
            from: normalizedExclusions[currentExclusionIndex].to,
            to: zone.to
          });
        } // we cut in the middle, we need to create more zones, annoying !


        if (normalizedExclusions[currentExclusionIndex].from > zone.from) {
          results.push({
            from: zone.from,
            to: normalizedExclusions[currentExclusionIndex].from
          });
        }

        zone.from = normalizedExclusions[currentExclusionIndex].to;
        zoneIndex--;
      }

      return results;
    }

    /**
     * XyExtract zones from a XY data
     *
     * @param data - Object that contains property x (an ordered increasing array) and y (an array)
     * @param options - options
     * @returns - Array of points
     */

    function xyExtract(data) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      xyCheck(data);
      const {
        x,
        y
      } = data;
      let {
        zones
      } = options;
      zones = zonesNormalize(zones);

      if (x === undefined || y === undefined || !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
      };
    }

    /**
     * Calculate integration
     *
     * @param data - Object that contains property x (an ordered increasing array) and y (an array)
     * @param options - Options
     * @returns - xyIntegration value on the specified range
     */

    function xyIntegration(data) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      xyCheck(data, {
        minLength: 1
      });
      const {
        x,
        y
      } = data;
      if (x.length === 1) 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;
    }

    function matrixCheck(data) {
      if (data.length === 0 || data[0].length === 0) {
        throw new RangeError('matrix should contain data');
      }

      const firstLength = data[0].length;

      for (let i = 1; i < data.length; i++) {
        if (data[i].length !== firstLength) {
          throw new RangeError('All rows should has the same length');
        }
      }
    }

    /**
     * Get min and max Z
     *
     * @param matrix - matrix [rows][cols].
     */

    function matrixMinMaxZ(matrix) {
      matrixCheck(matrix);
      const nbRows = matrix.length;
      const nbColumns = matrix[0].length;
      let min = matrix[0][0];
      let max = matrix[0][0];

      for (let column = 0; column < nbColumns; column++) {
        for (let row = 0; row < nbRows; row++) {
          if (matrix[row][column] < min) min = matrix[row][column];
          if (matrix[row][column] > max) max = matrix[row][column];
        }
      }

      return {
        min,
        max
      };
    }

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

      if (!isAnyArray(input)) {
        throw new TypeError('input must be an array');
      }

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

      var _options$fromIndex = options.fromIndex,
          fromIndex = _options$fromIndex === void 0 ? 0 : _options$fromIndex,
          _options$toIndex = options.toIndex,
          toIndex = _options$toIndex === void 0 ? input.length : _options$toIndex;

      if (fromIndex < 0 || fromIndex >= input.length || !Number.isInteger(fromIndex)) {
        throw new Error('fromIndex must be a positive integer smaller than length');
      }

      if (toIndex <= fromIndex || toIndex > input.length || !Number.isInteger(toIndex)) {
        throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length');
      }

      var maxValue = input[fromIndex];

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

      return maxValue;
    }

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

      if (!isAnyArray(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(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(options.output)) {
          throw new TypeError('output option must be an array if specified');
        }

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

      var currentMin = min(input);
      var currentMax = max(input);

      if (currentMin === currentMax) {
        throw new RangeError('minimum and maximum input values are equal. Cannot rescale a constant array');
      }

      var _options$min = options.min,
          minValue = _options$min === void 0 ? options.autoMinMax ? currentMin : 0 : _options$min,
          _options$max = options.max,
          maxValue = _options$max === void 0 ? options.autoMinMax ? currentMax : 1 : _options$max;

      if (minValue >= maxValue) {
        throw new RangeError('min option must be smaller than max option');
      }

      var factor = (maxValue - minValue) / (currentMax - currentMin);

      for (var i = 0; i < input.length; i++) {
        output[i] = (input[i] - currentMin) * factor + minValue;
      }

      return output;
    }

    const indent = ' '.repeat(2);
    const indentData = ' '.repeat(4);
    function inspectMatrix() {
      return inspectMatrixWithOptions(this);
    }
    function inspectMatrixWithOptions(matrix) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      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 checkRowIndices(matrix, rowIndices) {
      if (!isAnyArray(rowIndices)) {
        throw new TypeError('row indices must be an array');
      }

      for (let i = 0; i < rowIndices.length; i++) {
        if (rowIndices[i] < 0 || rowIndices[i] >= matrix.rows) {
          throw new RangeError('row indices are out of range');
        }
      }
    }
    function checkColumnIndices(matrix, columnIndices) {
      if (!isAnyArray(columnIndices)) {
        throw new TypeError('column indices must be an array');
      }

      for (let i = 0; i < columnIndices.length; i++) {
        if (columnIndices[i] < 0 || columnIndices[i] >= matrix.columns) {
          throw new RangeError('column indices are out of range');
        }
      }
    }
    function checkRange(matrix, startRow, endRow, startColumn, endColumn) {
      if (arguments.length !== 5) {
        throw new RangeError('expected 4 arguments');
      }

      checkNumber('startRow', startRow);
      checkNumber('endRow', endRow);
      checkNumber('startColumn', startColumn);
      checkNumber('endColumn', endColumn);

      if (startRow > endRow || startColumn > endColumn || startRow < 0 || startRow >= matrix.rows || endRow < 0 || endRow >= matrix.rows || startColumn < 0 || startColumn >= matrix.columns || endColumn < 0 || endColumn >= matrix.columns) {
        throw new RangeError('Submatrix indices are out of range');
      }
    }
    function newArray$1(length) {
      let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 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$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(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(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$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(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(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(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, 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(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(rows, columns);
      }

      static ones(rows, columns) {
        return new Matrix(rows, columns).fill(1);
      }

      static rand(rows, columns) {
        let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }

        const {
          random = Math.random
        } = options;
        let matrix = new Matrix(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) {
        let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

        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(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(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(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() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        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(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.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.columnVector(this.getColumn(index));
      }

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

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

        return this;
      }

      swapColumns(column1, column2) {
        checkColumnIndex(this, column1);
        checkColumnIndex(this, column2);

        for (let i = 0; i < this.rows; i++) {
          let temp = this.get(i, column1);
          this.set(i, column1, this.get(i, column2));
          this.set(i, column2, temp);
        }

        return this;
      }

      addRowVector(vector) {
        vector = checkRowVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) + vector[j]);
          }
        }

        return this;
      }

      subRowVector(vector) {
        vector = checkRowVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) - vector[j]);
          }
        }

        return this;
      }

      mulRowVector(vector) {
        vector = checkRowVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) * vector[j]);
          }
        }

        return this;
      }

      divRowVector(vector) {
        vector = checkRowVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) / vector[j]);
          }
        }

        return this;
      }

      addColumnVector(vector) {
        vector = checkColumnVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) + vector[i]);
          }
        }

        return this;
      }

      subColumnVector(vector) {
        vector = checkColumnVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) - vector[i]);
          }
        }

        return this;
      }

      mulColumnVector(vector) {
        vector = checkColumnVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) * vector[i]);
          }
        }

        return this;
      }

      divColumnVector(vector) {
        vector = checkColumnVector(this, vector);

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) / vector[i]);
          }
        }

        return this;
      }

      mulRow(index, value) {
        checkRowIndex(this, index);

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

        return this;
      }

      mulColumn(index, value) {
        checkColumnIndex(this, index);

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

        return this;
      }

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

        switch (by) {
          case 'row':
            {
              const max = new Array(this.rows).fill(Number.NEGATIVE_INFINITY);

              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) > max[row]) {
                    max[row] = this.get(row, column);
                  }
                }
              }

              return max;
            }

          case 'column':
            {
              const max = new Array(this.columns).fill(Number.NEGATIVE_INFINITY);

              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) > max[column]) {
                    max[column] = this.get(row, column);
                  }
                }
              }

              return max;
            }

          case undefined:
            {
              let max = this.get(0, 0);

              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) > max) {
                    max = this.get(row, column);
                  }
                }
              }

              return max;
            }

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

      maxIndex() {
        checkNonEmpty(this);
        let v = this.get(0, 0);
        let idx = [0, 0];

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            if (this.get(i, j) > v) {
              v = this.get(i, j);
              idx[0] = i;
              idx[1] = j;
            }
          }
        }

        return idx;
      }

      min(by) {
        if (this.isEmpty()) {
          return NaN;
        }

        switch (by) {
          case 'row':
            {
              const min = new Array(this.rows).fill(Number.POSITIVE_INFINITY);

              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) < min[row]) {
                    min[row] = this.get(row, column);
                  }
                }
              }

              return min;
            }

          case 'column':
            {
              const min = new Array(this.columns).fill(Number.POSITIVE_INFINITY);

              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) < min[column]) {
                    min[column] = this.get(row, column);
                  }
                }
              }

              return min;
            }

          case undefined:
            {
              let min = this.get(0, 0);

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

              return min;
            }

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

      minIndex() {
        checkNonEmpty(this);
        let v = this.get(0, 0);
        let idx = [0, 0];

        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            if (this.get(i, j) < v) {
              v = this.get(i, j);
              idx[0] = i;
              idx[1] = j;
            }
          }
        }

        return idx;
      }

      maxRow(row) {
        checkRowIndex(this, row);

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

        let v = this.get(row, 0);

        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) > v) {
            v = this.get(row, i);
          }
        }

        return v;
      }

      maxRowIndex(row) {
        checkRowIndex(this, row);
        checkNonEmpty(this);
        let v = this.get(row, 0);
        let idx = [row, 0];

        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) > v) {
            v = this.get(row, i);
            idx[1] = i;
          }
        }

        return idx;
      }

      minRow(row) {
        checkRowIndex(this, row);

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

        let v = this.get(row, 0);

        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) < v) {
            v = this.get(row, i);
          }
        }

        return v;
      }

      minRowIndex(row) {
        checkRowIndex(this, row);
        checkNonEmpty(this);
        let v = this.get(row, 0);
        let idx = [row, 0];

        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) < v) {
            v = this.get(row, i);
            idx[1] = i;
          }
        }

        return idx;
      }

      maxColumn(column) {
        checkColumnIndex(this, column);

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

        let v = this.get(0, column);

        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) > v) {
            v = this.get(i, column);
          }
        }

        return v;
      }

      maxColumnIndex(column) {
        checkColumnIndex(this, column);
        checkNonEmpty(this);
        let v = this.get(0, column);
        let idx = [0, column];

        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) > v) {
            v = this.get(i, column);
            idx[0] = i;
          }
        }

        return idx;
      }

      minColumn(column) {
        checkColumnIndex(this, column);

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

        let v = this.get(0, column);

        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) < v) {
            v = this.get(i, column);
          }
        }

        return v;
      }

      minColumnIndex(column) {
        checkColumnIndex(this, column);
        checkNonEmpty(this);
        let v = this.get(0, column);
        let idx = [0, column];

        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) < v) {
            v = this.get(i, column);
            idx[0] = i;
          }
        }

        return idx;
      }

      diag() {
        let min = Math.min(this.rows, this.columns);
        let diag = [];

        for (let i = 0; i < min; i++) {
          diag.push(this.get(i, i));
        }

        return diag;
      }

      norm() {
        let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '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.checkMatrix(other);
        let m = this.rows;
        let n = this.columns;
        let p = other.columns;
        let result = new Matrix(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.checkMatrix(other);
        let result = new Matrix(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.checkMatrix(other);
        let result = new Matrix(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.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() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        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(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() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        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(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.checkMatrix(other);
        let m = this.rows;
        let n = this.columns;
        let p = other.rows;
        let q = other.columns;
        let result = new Matrix(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.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.eye(n, n));
        let IxB = Matrix.eye(m, m).kroneckerProduct(other);
        return AxI.add(IxB);
      }

      transpose() {
        let result = new Matrix(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() {
        let compareFunction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : compareNumbers;

        for (let i = 0; i < this.rows; i++) {
          this.setRow(i, this.getRow(i).sort(compareFunction));
        }

        return this;
      }

      sortColumns() {
        let compareFunction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 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(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(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(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.checkMatrix(matrix);

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

        let endRow = startRow + matrix.rows - 1;
        let endColumn = startColumn + matrix.columns - 1;
        checkRange(this, startRow, endRow, startColumn, endColumn);

        for (let i = 0; i < matrix.rows; i++) {
          for (let j = 0; j < matrix.columns; j++) {
            this.set(startRow + i, startColumn + j, matrix.get(i, j));
          }
        }

        return this;
      }

      selection(rowIndices, columnIndices) {
        checkRowIndices(this, rowIndices);
        checkColumnIndices(this, columnIndices);
        let newMatrix = new Matrix(rowIndices.length, columnIndices.length);

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

          for (let j = 0; j < columnIndices.length; j++) {
            let columnIndex = columnIndices[j];
            newMatrix.set(i, j, this.get(rowIndex, columnIndex));
          }
        }

        return newMatrix;
      }

      trace() {
        let min = Math.min(this.rows, this.columns);
        let trace = 0;

        for (let i = 0; i < min; i++) {
          trace += this.get(i, i);
        }

        return trace;
      }

      clone() {
        let newMatrix = new Matrix(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) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }

        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }

        const {
          unbiased = true,
          mean = this.mean(by)
        } = options;

        if (typeof unbiased !== 'boolean') {
          throw new TypeError('unbiased must be a boolean');
        }

        switch (by) {
          case 'row':
            {
              if (!isAnyArray(mean)) {
                throw new TypeError('mean must be an array');
              }

              return varianceByRow(this, unbiased, mean);
            }

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

              return varianceByColumn(this, unbiased, mean);
            }

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

              return varianceAll(this, unbiased, mean);
            }

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

      standardDeviation(by, options) {
        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }

        const variance = this.variance(by, options);

        if (by === undefined) {
          return Math.sqrt(variance);
        } else {
          for (let i = 0; i < variance.length; i++) {
            variance[i] = Math.sqrt(variance[i]);
          }

          return variance;
        }
      }

      center(by) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }

        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }

        const {
          center = this.mean(by)
        } = options;

        switch (by) {
          case 'row':
            {
              if (!isAnyArray(center)) {
                throw new TypeError('center must be an array');
              }

              centerByRow(this, center);
              return this;
            }

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

              centerByColumn(this, center);
              return this;
            }

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

              centerAll(this, center);
              return this;
            }

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

      scale(by) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }

        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }

        let scale = options.scale;

        switch (by) {
          case 'row':
            {
              if (scale === undefined) {
                scale = getScaleByRow(this);
              } else if (!isAnyArray(scale)) {
                throw new TypeError('scale must be an array');
              }

              scaleByRow(this, scale);
              return this;
            }

          case 'column':
            {
              if (scale === undefined) {
                scale = getScaleByColumn(this);
              } else if (!isAnyArray(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;
    }

    function isArrayOfNumbers(array) {
      return array.every(element => {
        return typeof element === 'number';
      });
    } // Synonyms


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

        if (Matrix.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 (isAnyArray(nRows)) {
          // Copy the values from the 2D array
          const arrayData = nRows;
          nRows = arrayData.length;
          nColumns = nRows ? arrayData[0].length : 0;

          if (typeof nColumns !== 'number') {
            throw new TypeError('Data must be a 2D array with at least one element');
          }

          this.data = [];

          for (let i = 0; i < nRows; i++) {
            if (arrayData[i].length !== nColumns) {
              throw new RangeError('Inconsistent array dimensions');
            }

            if (!isArrayOfNumbers(arrayData[i])) {
              throw new TypeError('Input data contains non-numeric values');
            }

            this.data.push(Float64Array.from(arrayData[i]));
          }
        } 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);

    class WrapperMatrix2D extends AbstractMatrix {
      constructor(data) {
        super();
        this.data = data;
        this.rows = data.length;
        this.columns = data[0].length;
      }

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

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

    }

    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.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(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(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.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(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(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) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        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(m, nu);
        let V = new Matrix(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.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.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.diag(value));
      }

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

    }

    function inverse(matrix) {
      let useSVD = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
      matrix = WrapperMatrix2D.checkMatrix(matrix);

      if (useSVD) {
        return new SingularValueDecomposition(matrix).inverse();
      } else {
        return solve(matrix, Matrix.eye(matrix.rows));
      }
    }
    function solve(leftHandSide, rightHandSide) {
      let useSVD = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 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);
      }
    }

    class EigenvalueDecomposition {
      constructor(matrix) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        const {
          assumeSymmetric = false
        } = options;
        matrix = WrapperMatrix2D.checkMatrix(matrix);

        if (!matrix.isSquare()) {
          throw new Error('Matrix is not a square matrix');
        }

        if (matrix.isEmpty()) {
          throw new Error('Matrix must be non-empty');
        }

        let n = matrix.columns;
        let V = new Matrix(n, n);
        let d = new Float64Array(n);
        let e = new Float64Array(n);
        let value = matrix;
        let i, j;
        let isSymmetric = false;

        if (assumeSymmetric) {
          isSymmetric = true;
        } else {
          isSymmetric = matrix.isSymmetric();
        }

        if (isSymmetric) {
          for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
              V.set(i, j, value.get(i, j));
            }
          }

          tred2(n, e, d, V);
          tql2(n, e, d, V);
        } else {
          let H = new Matrix(n, n);
          let ort = new Float64Array(n);

          for (j = 0; j < n; j++) {
            for (i = 0; i < n; i++) {
              H.set(i, j, value.get(i, j));
            }
          }

          orthes(n, H, ort, V);
          hqr2(n, e, d, V, H);
        }

        this.n = n;
        this.e = e;
        this.d = d;
        this.V = V;
      }

      get realEigenvalues() {
        return Array.from(this.d);
      }

      get imaginaryEigenvalues() {
        return Array.from(this.e);
      }

      get eigenvectorMatrix() {
        return this.V;
      }

      get diagonalMatrix() {
        let n = this.n;
        let e = this.e;
        let d = this.d;
        let X = new Matrix(n, n);
        let i, j;

        for (i = 0; i < n; i++) {
          for (j = 0; j < n; j++) {
            X.set(i, j, 0);
          }

          X.set(i, i, d[i]);

          if (e[i] > 0) {
            X.set(i, i + 1, e[i]);
          } else if (e[i] < 0) {
            X.set(i, i - 1, e[i]);
          }
        }

        return X;
      }

    }

    function tred2(n, e, d, V) {
      let f, g, h, i, j, k, hh, scale;

      for (j = 0; j < n; j++) {
        d[j] = V.get(n - 1, j);
      }

      for (i = n - 1; i > 0; i--) {
        scale = 0;
        h = 0;

        for (k = 0; k < i; k++) {
          scale = scale + Math.abs(d[k]);
        }

        if (scale === 0) {
          e[i] = d[i - 1];

          for (j = 0; j < i; j++) {
            d[j] = V.get(i - 1, j);
            V.set(i, j, 0);
            V.set(j, i, 0);
          }
        } else {
          for (k = 0; k < i; k++) {
            d[k] /= scale;
            h += d[k] * d[k];
          }

          f = d[i - 1];
          g = Math.sqrt(h);

          if (f > 0) {
            g = -g;
          }

          e[i] = scale * g;
          h = h - f * g;
          d[i - 1] = f - g;

          for (j = 0; j < i; j++) {
            e[j] = 0;
          }

          for (j = 0; j < i; j++) {
            f = d[j];
            V.set(j, i, f);
            g = e[j] + V.get(j, j) * f;

            for (k = j + 1; k <= i - 1; k++) {
              g += V.get(k, j) * d[k];
              e[k] += V.get(k, j) * f;
            }

            e[j] = g;
          }

          f = 0;

          for (j = 0; j < i; j++) {
            e[j] /= h;
            f += e[j] * d[j];
          }

          hh = f / (h + h);

          for (j = 0; j < i; j++) {
            e[j] -= hh * d[j];
          }

          for (j = 0; j < i; j++) {
            f = d[j];
            g = e[j];

            for (k = j; k <= i - 1; k++) {
              V.set(k, j, V.get(k, j) - (f * e[k] + g * d[k]));
            }

            d[j] = V.get(i - 1, j);
            V.set(i, j, 0);
          }
        }

        d[i] = h;
      }

      for (i = 0; i < n - 1; i++) {
        V.set(n - 1, i, V.get(i, i));
        V.set(i, i, 1);
        h = d[i + 1];

        if (h !== 0) {
          for (k = 0; k <= i; k++) {
            d[k] = V.get(k, i + 1) / h;
          }

          for (j = 0; j <= i; j++) {
            g = 0;

            for (k = 0; k <= i; k++) {
              g += V.get(k, i + 1) * V.get(k, j);
            }

            for (k = 0; k <= i; k++) {
              V.set(k, j, V.get(k, j) - g * d[k]);
            }
          }
        }

        for (k = 0; k <= i; k++) {
          V.set(k, i + 1, 0);
        }
      }

      for (j = 0; j < n; j++) {
        d[j] = V.get(n - 1, j);
        V.set(n - 1, j, 0);
      }

      V.set(n - 1, n - 1, 1);
      e[0] = 0;
    }

    function tql2(n, e, d, V) {
      let g, h, i, j, k, l, m, p, r, dl1, c, c2, c3, el1, s, s2;

      for (i = 1; i < n; i++) {
        e[i - 1] = e[i];
      }

      e[n - 1] = 0;
      let f = 0;
      let tst1 = 0;
      let eps = Number.EPSILON;

      for (l = 0; l < n; l++) {
        tst1 = Math.max(tst1, Math.abs(d[l]) + Math.abs(e[l]));
        m = l;

        while (m < n) {
          if (Math.abs(e[m]) <= eps * tst1) {
            break;
          }

          m++;
        }

        if (m > l) {

          do {
            g = d[l];
            p = (d[l + 1] - g) / (2 * e[l]);
            r = hypotenuse(p, 1);

            if (p < 0) {
              r = -r;
            }

            d[l] = e[l] / (p + r);
            d[l + 1] = e[l] * (p + r);
            dl1 = d[l + 1];
            h = g - d[l];

            for (i = l + 2; i < n; i++) {
              d[i] -= h;
            }

            f = f + h;
            p = d[m];
            c = 1;
            c2 = c;
            c3 = c;
            el1 = e[l + 1];
            s = 0;
            s2 = 0;

            for (i = m - 1; i >= l; i--) {
              c3 = c2;
              c2 = c;
              s2 = s;
              g = c * e[i];
              h = c * p;
              r = hypotenuse(p, e[i]);
              e[i + 1] = s * r;
              s = e[i] / r;
              c = p / r;
              p = c * d[i] - s * g;
              d[i + 1] = h + s * (c * g + s * d[i]);

              for (k = 0; k < n; k++) {
                h = V.get(k, i + 1);
                V.set(k, i + 1, s * V.get(k, i) + c * h);
                V.set(k, i, c * V.get(k, i) - s * h);
              }
            }

            p = -s * s2 * c3 * el1 * e[l] / dl1;
            e[l] = s * p;
            d[l] = c * p;
          } while (Math.abs(e[l]) > eps * tst1);
        }

        d[l] = d[l] + f;
        e[l] = 0;
      }

      for (i = 0; i < n - 1; i++) {
        k = i;
        p = d[i];

        for (j = i + 1; j < n; j++) {
          if (d[j] < p) {
            k = j;
            p = d[j];
          }
        }

        if (k !== i) {
          d[k] = d[i];
          d[i] = p;

          for (j = 0; j < n; j++) {
            p = V.get(j, i);
            V.set(j, i, V.get(j, k));
            V.set(j, k, p);
          }
        }
      }
    }

    function orthes(n, H, ort, V) {
      let low = 0;
      let high = n - 1;
      let f, g, h, i, j, m;
      let scale;

      for (m = low + 1; m <= high - 1; m++) {
        scale = 0;

        for (i = m; i <= high; i++) {
          scale = scale + Math.abs(H.get(i, m - 1));
        }

        if (scale !== 0) {
          h = 0;

          for (i = high; i >= m; i--) {
            ort[i] = H.get(i, m - 1) / scale;
            h += ort[i] * ort[i];
          }

          g = Math.sqrt(h);

          if (ort[m] > 0) {
            g = -g;
          }

          h = h - ort[m] * g;
          ort[m] = ort[m] - g;

          for (j = m; j < n; j++) {
            f = 0;

            for (i = high; i >= m; i--) {
              f += ort[i] * H.get(i, j);
            }

            f = f / h;

            for (i = m; i <= high; i++) {
              H.set(i, j, H.get(i, j) - f * ort[i]);
            }
          }

          for (i = 0; i <= high; i++) {
            f = 0;

            for (j = high; j >= m; j--) {
              f += ort[j] * H.get(i, j);
            }

            f = f / h;

            for (j = m; j <= high; j++) {
              H.set(i, j, H.get(i, j) - f * ort[j]);
            }
          }

          ort[m] = scale * ort[m];
          H.set(m, m - 1, scale * g);
        }
      }

      for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
          V.set(i, j, i === j ? 1 : 0);
        }
      }

      for (m = high - 1; m >= low + 1; m--) {
        if (H.get(m, m - 1) !== 0) {
          for (i = m + 1; i <= high; i++) {
            ort[i] = H.get(i, m - 1);
          }

          for (j = m; j <= high; j++) {
            g = 0;

            for (i = m; i <= high; i++) {
              g += ort[i] * V.get(i, j);
            }

            g = g / ort[m] / H.get(m, m - 1);

            for (i = m; i <= high; i++) {
              V.set(i, j, V.get(i, j) + g * ort[i]);
            }
          }
        }
      }
    }

    function hqr2(nn, e, d, V, H) {
      let n = nn - 1;
      let low = 0;
      let high = nn - 1;
      let eps = Number.EPSILON;
      let exshift = 0;
      let norm = 0;
      let p = 0;
      let q = 0;
      let r = 0;
      let s = 0;
      let z = 0;
      let iter = 0;
      let i, j, k, l, m, t, w, x, y;
      let ra, sa, vr, vi;
      let notlast, cdivres;

      for (i = 0; i < nn; i++) {
        if (i < low || i > high) {
          d[i] = H.get(i, i);
          e[i] = 0;
        }

        for (j = Math.max(i - 1, 0); j < nn; j++) {
          norm = norm + Math.abs(H.get(i, j));
        }
      }

      while (n >= low) {
        l = n;

        while (l > low) {
          s = Math.abs(H.get(l - 1, l - 1)) + Math.abs(H.get(l, l));

          if (s === 0) {
            s = norm;
          }

          if (Math.abs(H.get(l, l - 1)) < eps * s) {
            break;
          }

          l--;
        }

        if (l === n) {
          H.set(n, n, H.get(n, n) + exshift);
          d[n] = H.get(n, n);
          e[n] = 0;
          n--;
          iter = 0;
        } else if (l === n - 1) {
          w = H.get(n, n - 1) * H.get(n - 1, n);
          p = (H.get(n - 1, n - 1) - H.get(n, n)) / 2;
          q = p * p + w;
          z = Math.sqrt(Math.abs(q));
          H.set(n, n, H.get(n, n) + exshift);
          H.set(n - 1, n - 1, H.get(n - 1, n - 1) + exshift);
          x = H.get(n, n);

          if (q >= 0) {
            z = p >= 0 ? p + z : p - z;
            d[n - 1] = x + z;
            d[n] = d[n - 1];

            if (z !== 0) {
              d[n] = x - w / z;
            }

            e[n - 1] = 0;
            e[n] = 0;
            x = H.get(n, n - 1);
            s = Math.abs(x) + Math.abs(z);
            p = x / s;
            q = z / s;
            r = Math.sqrt(p * p + q * q);
            p = p / r;
            q = q / r;

            for (j = n - 1; j < nn; j++) {
              z = H.get(n - 1, j);
              H.set(n - 1, j, q * z + p * H.get(n, j));
              H.set(n, j, q * H.get(n, j) - p * z);
            }

            for (i = 0; i <= n; i++) {
              z = H.get(i, n - 1);
              H.set(i, n - 1, q * z + p * H.get(i, n));
              H.set(i, n, q * H.get(i, n) - p * z);
            }

            for (i = low; i <= high; i++) {
              z = V.get(i, n - 1);
              V.set(i, n - 1, q * z + p * V.get(i, n));
              V.set(i, n, q * V.get(i, n) - p * z);
            }
          } else {
            d[n - 1] = x + p;
            d[n] = x + p;
            e[n - 1] = z;
            e[n] = -z;
          }

          n = n - 2;
          iter = 0;
        } else {
          x = H.get(n, n);
          y = 0;
          w = 0;

          if (l < n) {
            y = H.get(n - 1, n - 1);
            w = H.get(n, n - 1) * H.get(n - 1, n);
          }

          if (iter === 10) {
            exshift += x;

            for (i = low; i <= n; i++) {
              H.set(i, i, H.get(i, i) - x);
            }

            s = Math.abs(H.get(n, n - 1)) + Math.abs(H.get(n - 1, n - 2));
            x = y = 0.75 * s;
            w = -0.4375 * s * s;
          }

          if (iter === 30) {
            s = (y - x) / 2;
            s = s * s + w;

            if (s > 0) {
              s = Math.sqrt(s);

              if (y < x) {
                s = -s;
              }

              s = x - w / ((y - x) / 2 + s);

              for (i = low; i <= n; i++) {
                H.set(i, i, H.get(i, i) - s);
              }

              exshift += s;
              x = y = w = 0.964;
            }
          }

          iter = iter + 1;
          m = n - 2;

          while (m >= l) {
            z = H.get(m, m);
            r = x - z;
            s = y - z;
            p = (r * s - w) / H.get(m + 1, m) + H.get(m, m + 1);
            q = H.get(m + 1, m + 1) - z - r - s;
            r = H.get(m + 2, m + 1);
            s = Math.abs(p) + Math.abs(q) + Math.abs(r);
            p = p / s;
            q = q / s;
            r = r / s;

            if (m === l) {
              break;
            }

            if (Math.abs(H.get(m, m - 1)) * (Math.abs(q) + Math.abs(r)) < eps * (Math.abs(p) * (Math.abs(H.get(m - 1, m - 1)) + Math.abs(z) + Math.abs(H.get(m + 1, m + 1))))) {
              break;
            }

            m--;
          }

          for (i = m + 2; i <= n; i++) {
            H.set(i, i - 2, 0);

            if (i > m + 2) {
              H.set(i, i - 3, 0);
            }
          }

          for (k = m; k <= n - 1; k++) {
            notlast = k !== n - 1;

            if (k !== m) {
              p = H.get(k, k - 1);
              q = H.get(k + 1, k - 1);
              r = notlast ? H.get(k + 2, k - 1) : 0;
              x = Math.abs(p) + Math.abs(q) + Math.abs(r);

              if (x !== 0) {
                p = p / x;
                q = q / x;
                r = r / x;
              }
            }

            if (x === 0) {
              break;
            }

            s = Math.sqrt(p * p + q * q + r * r);

            if (p < 0) {
              s = -s;
            }

            if (s !== 0) {
              if (k !== m) {
                H.set(k, k - 1, -s * x);
              } else if (l !== m) {
                H.set(k, k - 1, -H.get(k, k - 1));
              }

              p = p + s;
              x = p / s;
              y = q / s;
              z = r / s;
              q = q / p;
              r = r / p;

              for (j = k; j < nn; j++) {
                p = H.get(k, j) + q * H.get(k + 1, j);

                if (notlast) {
                  p = p + r * H.get(k + 2, j);
                  H.set(k + 2, j, H.get(k + 2, j) - p * z);
                }

                H.set(k, j, H.get(k, j) - p * x);
                H.set(k + 1, j, H.get(k + 1, j) - p * y);
              }

              for (i = 0; i <= Math.min(n, k + 3); i++) {
                p = x * H.get(i, k) + y * H.get(i, k + 1);

                if (notlast) {
                  p = p + z * H.get(i, k + 2);
                  H.set(i, k + 2, H.get(i, k + 2) - p * r);
                }

                H.set(i, k, H.get(i, k) - p);
                H.set(i, k + 1, H.get(i, k + 1) - p * q);
              }

              for (i = low; i <= high; i++) {
                p = x * V.get(i, k) + y * V.get(i, k + 1);

                if (notlast) {
                  p = p + z * V.get(i, k + 2);
                  V.set(i, k + 2, V.get(i, k + 2) - p * r);
                }

                V.set(i, k, V.get(i, k) - p);
                V.set(i, k + 1, V.get(i, k + 1) - p * q);
              }
            }
          }
        }
      }

      if (norm === 0) {
        return;
      }

      for (n = nn - 1; n >= 0; n--) {
        p = d[n];
        q = e[n];

        if (q === 0) {
          l = n;
          H.set(n, n, 1);

          for (i = n - 1; i >= 0; i--) {
            w = H.get(i, i) - p;
            r = 0;

            for (j = l; j <= n; j++) {
              r = r + H.get(i, j) * H.get(j, n);
            }

            if (e[i] < 0) {
              z = w;
              s = r;
            } else {
              l = i;

              if (e[i] === 0) {
                H.set(i, n, w !== 0 ? -r / w : -r / (eps * norm));
              } else {
                x = H.get(i, i + 1);
                y = H.get(i + 1, i);
                q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
                t = (x * s - z * r) / q;
                H.set(i, n, t);
                H.set(i + 1, n, Math.abs(x) > Math.abs(z) ? (-r - w * t) / x : (-s - y * t) / z);
              }

              t = Math.abs(H.get(i, n));

              if (eps * t * t > 1) {
                for (j = i; j <= n; j++) {
                  H.set(j, n, H.get(j, n) / t);
                }
              }
            }
          }
        } else if (q < 0) {
          l = n - 1;

          if (Math.abs(H.get(n, n - 1)) > Math.abs(H.get(n - 1, n))) {
            H.set(n - 1, n - 1, q / H.get(n, n - 1));
            H.set(n - 1, n, -(H.get(n, n) - p) / H.get(n, n - 1));
          } else {
            cdivres = cdiv(0, -H.get(n - 1, n), H.get(n - 1, n - 1) - p, q);
            H.set(n - 1, n - 1, cdivres[0]);
            H.set(n - 1, n, cdivres[1]);
          }

          H.set(n, n - 1, 0);
          H.set(n, n, 1);

          for (i = n - 2; i >= 0; i--) {
            ra = 0;
            sa = 0;

            for (j = l; j <= n; j++) {
              ra = ra + H.get(i, j) * H.get(j, n - 1);
              sa = sa + H.get(i, j) * H.get(j, n);
            }

            w = H.get(i, i) - p;

            if (e[i] < 0) {
              z = w;
              r = ra;
              s = sa;
            } else {
              l = i;

              if (e[i] === 0) {
                cdivres = cdiv(-ra, -sa, w, q);
                H.set(i, n - 1, cdivres[0]);
                H.set(i, n, cdivres[1]);
              } else {
                x = H.get(i, i + 1);
                y = H.get(i + 1, i);
                vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
                vi = (d[i] - p) * 2 * q;

                if (vr === 0 && vi === 0) {
                  vr = eps * norm * (Math.abs(w) + Math.abs(q) + Math.abs(x) + Math.abs(y) + Math.abs(z));
                }

                cdivres = cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi);
                H.set(i, n - 1, cdivres[0]);
                H.set(i, n, cdivres[1]);

                if (Math.abs(x) > Math.abs(z) + Math.abs(q)) {
                  H.set(i + 1, n - 1, (-ra - w * H.get(i, n - 1) + q * H.get(i, n)) / x);
                  H.set(i + 1, n, (-sa - w * H.get(i, n) - q * H.get(i, n - 1)) / x);
                } else {
                  cdivres = cdiv(-r - y * H.get(i, n - 1), -s - y * H.get(i, n), z, q);
                  H.set(i + 1, n - 1, cdivres[0]);
                  H.set(i + 1, n, cdivres[1]);
                }
              }

              t = Math.max(Math.abs(H.get(i, n - 1)), Math.abs(H.get(i, n)));

              if (eps * t * t > 1) {
                for (j = i; j <= n; j++) {
                  H.set(j, n - 1, H.get(j, n - 1) / t);
                  H.set(j, n, H.get(j, n) / t);
                }
              }
            }
          }
        }
      }

      for (i = 0; i < nn; i++) {
        if (i < low || i > high) {
          for (j = i; j < nn; j++) {
            V.set(i, j, H.get(i, j));
          }
        }
      }

      for (j = nn - 1; j >= low; j--) {
        for (i = low; i <= high; i++) {
          z = 0;

          for (k = low; k <= Math.min(j, high); k++) {
            z = z + V.get(i, k) * H.get(k, j);
          }

          V.set(i, j, z);
        }
      }
    }

    function cdiv(xr, xi, yr, yi) {
      let r, d;

      if (Math.abs(yr) > Math.abs(yi)) {
        r = yi / yr;
        d = yr + r * yi;
        return [(xr + r * xi) / d, (xi - r * xr) / d];
      } else {
        r = yr / yi;
        d = yi + r * yr;
        return [(r * xr + xi) / d, (r * xi - xr) / d];
      }
    }

    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() {
        let seed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 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;
      }

    }

    /**
     * Create a random array of numbers of a specific length
     *
     * @return - array of random floats normally distributed
     */

    let spare;
    let hasSpare = false;
    function createRandomArray() {
      let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let {
        mean = 0,
        standardDeviation = 1,
        length = 1000,
        range = 1,
        seed,
        distribution = 'normal'
      } = options;
      const generator = new XSadd(seed);
      let returnArray = new Float64Array(length);

      switch (distribution) {
        case 'normal':
          for (let i = 0; i < length; i++) {
            returnArray[i] = generateGaussian(mean, standardDeviation, generator);
          }

          break;

        case 'uniform':
          for (let i = 0; i < length; i++) {
            returnArray[i] = (generator.random() - 0.5) * range + mean;
          }

          break;

        default:
          // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
          throw new Error(`unknown distribution: ${distribution}`);
      }

      return returnArray;
    }

    function generateGaussian(mean, standardDeviation, generator) {
      let val, u, v, s;

      if (hasSpare) {
        hasSpare = false;
        val = spare * standardDeviation + mean;
      } else {
        do {
          u = generator.random() * 2 - 1;
          v = generator.random() * 2 - 1;
          s = u * u + v * v;
        } while (s >= 1 || s === 0);

        s = Math.sqrt(-2.0 * Math.log(s) / s);
        spare = v * s;
        hasSpare = true;
        val = mean + standardDeviation * u * s;
      }

      return val;
    }

    function addNoise(data) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        seed = 0,
        distribution = 'normal',
        percent = 1
      } = options;
      const range = xMaxValue(data.y) * percent / 100;
      const noise = createRandomArray({
        distribution,
        seed,
        mean: 0,
        standardDeviation: range,
        range,
        length: data.x.length
      });
      data.y = xAdd(data.y, noise);
      return data;
    }

    class SpectrumGenerator {
      constructor() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        const {
          from = 0,
          to = 1000,
          nbPoints = 10001,
          peakWidthFct,
          shape = {
            kind: 'gaussian',
            fwhm: 5
          }
        } = options;
        this.from = from;
        this.to = to;
        this.nbPoints = nbPoints;
        this.interval = (this.to - this.from) / (this.nbPoints - 1);
        this.peakWidthFct = peakWidthFct;
        this.maxPeakHeight = Number.MIN_SAFE_INTEGER;
        this.data = {
          x: new Float64Array(this.nbPoints),
          y: new Float64Array(this.nbPoints)
        };
        let shapeGenerator = getShape1D(shape);
        this.shape = shapeGenerator;
        assertNumber$2(this.from, 'from');
        assertNumber$2(this.to, 'to');
        assertInteger$1(this.nbPoints, 'nbPoints');

        if (this.to <= this.from) {
          throw new RangeError('to option must be larger than from');
        }

        if (this.peakWidthFct && typeof this.peakWidthFct !== 'function') {
          throw new TypeError('peakWidthFct option must be a function');
        }

        this.reset();
      }
      /**
       * Add a series of peaks to the spectrum.
       * @param peaks - Peaks to add.
       */


      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);
          }
        }
      }
      /**
       * Add a single peak to the spectrum.
       * A peak may be either defined as [x,y,fwhm,...] or as {x, y, shape}
       * @param peak
       * @param options
       */


      addPeak(peak) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

        if (Array.isArray(peak) && peak.length < 2) {
          throw new Error('peak must be an array with two (or three) values or an object with {x,y,width?}');
        }

        if (!Array.isArray(peak) && (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 peakFWHM;
        let peakWidth;
        let peakShapeOptions;

        if (Array.isArray(peak)) {
          [xPosition, intensity, peakFWHM, peakShapeOptions] = peak;
        } else {
          xPosition = peak.x;
          intensity = peak.y;
          peakWidth = peak.width;
          peakShapeOptions = peak.shape;
        }

        if (intensity > this.maxPeakHeight) this.maxPeakHeight = intensity;
        let {
          shape: shapeOptions
        } = options;

        if (peakShapeOptions) {
          shapeOptions = shapeOptions ? { ...shapeOptions,
            ...peakShapeOptions
          } : peakShapeOptions;
        }

        const shape = shapeOptions ? getShape1D(shapeOptions) : Object.assign(Object.create(Object.getPrototypeOf(this.shape)), this.shape);
        let {
          width,
          widthLeft,
          widthRight
        } = options;
        /*
         if we don't force the fwhm we just take the one from the shape
         however we have many way to force it:
         - use [x,y,fwhm]
         - define `width` that will be converted to fwhm
         - define `widthLeft` and `widthRight` to define asymmetric peaks
         - have a callback `peakWidthFct`
         This should evolve in the future because we will not always have `fwhm`
         */

        const fwhm = peakFWHM !== undefined ? peakFWHM : peakWidth ? shape.widthToFWHM(peakWidth) : this.peakWidthFct ? this.peakWidthFct(xPosition) : width !== undefined ? width : shape.fwhm;
        if (!widthLeft) widthLeft = fwhm;
        if (!widthRight) widthRight = fwhm;

        if (!widthLeft || !widthRight) {
          throw new Error('Width left or right is undefined or zero');
        }

        let factor = options.factor === undefined ? shape.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

        shape.fwhm = widthLeft;

        for (let index = firstPoint; index < Math.max(middlePoint, 0); index++) {
          this.data.y[index] += intensity * shape.fct(this.data.x[index] - xPosition);
        } // we calculate the right part of the gaussian


        shape.fwhm = widthRight;

        for (let index = Math.min(middlePoint, lastPoint); index <= lastPoint; index++) {
          this.data.y[index] += intensity * shape.fct(this.data.x[index] - xPosition);
        }
      }
      /**
       * Add a baseline to the spectrum.
       * @param baselineFct - Mathematical function producing the baseline you want.
       */


      addBaseline(baselineFct) {
        addBaseline(this.data, baselineFct);
        return this;
      }
      /**
       * Add noise to the spectrum.
       *
       * @param percent - Noise's amplitude in percents of the spectrum max value. Default: 1.
       */


      addNoise(options) {
        addNoise(this.data, options);
        return this;
      }
      /**
       * Get the generated spectrum.
       */


      getSpectrum() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        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;
        }
      }
      /**
       * Resets the generator with an empty spectrum.
       */


      reset() {
        const spectrum = this.data;

        for (let i = 0; i < this.nbPoints; i++) {
          spectrum.x[i] = this.from + i * this.interval;
        }

        return this;
      }

    }

    function assertInteger$1(value, name) {
      if (!Number.isInteger(value)) {
        throw new TypeError(`${name} option must be an integer`);
      }
    }

    function assertNumber$2(value, name) {
      if (!Number.isFinite(value)) {
        throw new TypeError(`${name} option must be a number`);
      }
    }
    /**
     * Generates a spectrum and returns it.
     * @param peaks - List of peaks to put in the spectrum.
     * @param options
     */


    function generateSpectrum(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        generator: generatorOptions,
        noise,
        baseline,
        threshold,
        peakOptions
      } = options;
      const generator = new SpectrumGenerator(generatorOptions);
      generator.addPeaks(peaks, peakOptions);
      if (baseline) generator.addBaseline(baseline);

      if (noise) {
        generator.addNoise(noise);
      }

      return generator.getSpectrum({
        threshold
      });
    }

    const axis2D = ['x', 'y'];
    const peakCoordinates = ['x', 'y', 'z'];

    const convertWidthToFWHM = (shape, width) => {
      const widthData = ensureXYNumber$1(width);

      for (let key of axis2D) {
        widthData[key] = shape.widthToFWHM(widthData[key]);
      }

      return widthData;
    };

    class Spectrum2DGenerator {
      constructor() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        let {
          from = 0,
          to = 100,
          nbPoints = 1001,
          peakWidthFct = () => 5,
          shape = {
            kind: 'gaussian'
          }
        } = options;
        from = ensureXYNumber$1(from);
        to = ensureXYNumber$1(to);
        nbPoints = ensureXYNumber$1(nbPoints);

        for (const axis of axis2D) {
          assertNumber$1(from[axis], `from-${axis}`);
          assertNumber$1(to[axis], `to-${axis}`);
          assertInteger(nbPoints[axis], `nbPoints-${axis}`);
        }

        this.from = from;
        this.to = to;
        this.nbPoints = nbPoints;
        this.interval = calculeIntervals(from, to, nbPoints);
        this.peakWidthFct = peakWidthFct;
        this.maxPeakHeight = Number.MIN_SAFE_INTEGER;
        let shapeGenerator = getShape2D(shape);
        this.shape = shapeGenerator;
        this.data = {
          x: new Float64Array(nbPoints.x),
          y: new Float64Array(nbPoints.y),
          z: createMatrix(this.nbPoints)
        };

        for (const axis of axis2D) {
          if (this.to[axis] <= this.from[axis]) {
            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 {
          let nbPeaks = peaks.x.length;

          for (const c of peakCoordinates) {
            if (peaks[c] && Array.isArray(peaks[c])) {
              if (nbPeaks !== peaks[c].length) {
                throw new Error('x, y, z should have the same length');
              }
            }
          }

          for (let i = 0; i < peaks.x.length; i++) {
            this.addPeak([peaks.x[i], peaks.y[i], peaks.z[i]], options);
          }
        }

        return this;
      }

      addPeak(peak) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

        if (Array.isArray(peak) && peak.length < 3) {
          throw new Error('peak must be an array with three (or four) values or an object with {x,y,z,width?}');
        }

        if (!Array.isArray(peak) && peakCoordinates.some(e => peak[e] === undefined)) {
          throw new Error('peak must be an array with three (or four) values or an object with {x,y,z,width?}');
        }

        let xPosition;
        let yPosition;
        let intensity;
        let peakFWHM;
        let peakWidth;
        let peakShapeOptions;

        if (Array.isArray(peak)) {
          [xPosition, yPosition, intensity, peakFWHM, peakShapeOptions] = peak;
        } else {
          xPosition = peak.x;
          yPosition = peak.y;
          intensity = peak.z;
          peakFWHM = peak.fwhm;
          peakWidth = peak.width;
          peakShapeOptions = peak.shape;
        }

        const position = {
          x: xPosition,
          y: yPosition
        };
        if (intensity > this.maxPeakHeight) this.maxPeakHeight = intensity;
        let {
          shape: shapeOptions,
          width
        } = options;

        if (peakShapeOptions) {
          shapeOptions = shapeOptions ? { ...shapeOptions,
            ...peakShapeOptions
          } : peakShapeOptions;
        }

        const shape = shapeOptions ? getShape2D(shapeOptions) : Object.assign(Object.create(Object.getPrototypeOf(this.shape)), JSON.parse(JSON.stringify(this.shape)));
        let {
          fwhm = peakFWHM !== undefined ? peakFWHM : peakWidth ? convertWidthToFWHM(shape, peakWidth) : width ? convertWidthToFWHM(shape, width) : this.peakWidthFct(xPosition, yPosition)
        } = options;
        fwhm = ensureXYNumber$1(fwhm);
        let factor = options.factor === undefined ? shape.getFactor() : options.factor;
        factor = ensureXYNumber$1(factor);
        const firstPoint = {
          x: 0,
          y: 0
        };
        const lastPoint = {
          x: 0,
          y: 0
        };

        for (const axis of axis2D) {
          const first = position[axis] - fwhm[axis] / 2 * factor[axis];
          const last = position[axis] + fwhm[axis] / 2 * factor[axis];
          firstPoint[axis] = Math.max(0, Math.floor((first - this.from[axis]) / this.interval[axis]));
          lastPoint[axis] = Math.min(this.nbPoints[axis], Math.ceil((last - this.from[axis]) / this.interval[axis]));
        }

        shape.fwhm = fwhm;

        for (let xIndex = firstPoint.x; xIndex < lastPoint.x; xIndex++) {
          for (let yIndex = firstPoint.y; yIndex < lastPoint.y; yIndex++) {
            const value = intensity * shape.fct(this.data.x[xIndex] - position.x, this.data.y[yIndex] - position.y);

            if (value > 1e-6) {
              this.data.z[yIndex][xIndex] += value;
            }
          }
        }

        return this;
      }

      getSpectrum() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        if (typeof options === 'boolean') {
          options = {
            copy: options
          };
        }

        const {
          copy = true
        } = options;
        let minMaxZ = matrixMinMaxZ(this.data.z);
        return {
          minX: this.from.x,
          maxX: this.to.x,
          maxY: this.to.y,
          minY: this.from.y,
          minZ: minMaxZ.min,
          maxZ: minMaxZ.max,
          z: copy ? this.data.z.slice() : this.data.z
        };
      }

      reset() {
        const spectrum = this.data;

        for (const axis of axis2D) {
          for (let i = 0; i < this.nbPoints[axis]; i++) {
            spectrum[axis][i] = this.from[axis] + i * this.interval[axis];
          }
        }

        for (let row of spectrum.z) {
          for (let j = 0; j < row.length; j++) {
            row[j] = 0;
          }
        }

        return this;
      }

    }
    function generateSpectrum2D(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        generator: generatorOptions,
        peaks: addPeaksOptions
      } = options;
      const generator = new Spectrum2DGenerator(generatorOptions);
      generator.addPeaks(peaks, addPeaksOptions);
      return generator.getSpectrum();
    }

    function ensureXYNumber$1(input) {
      return typeof input !== 'object' ? {
        x: input,
        y: input
      } : { ...input
      };
    }

    function calculeIntervals(from, to, nbPoints) {
      return {
        x: (to.x - from.x) / (nbPoints.x - 1),
        y: (to.y - from.y) / (nbPoints.y - 1)
      };
    }

    function assertInteger(value, name) {
      if (!Number.isInteger(value)) {
        throw new TypeError(`${name} option must be an integer`);
      }
    }

    function assertNumber$1(value, name) {
      if (!Number.isFinite(value)) {
        throw new TypeError(`${name} option must be a number`);
      }
    }

    function createMatrix(nbPoints) {
      const zMatrix = new Array(nbPoints.y);

      for (let i = 0; i < nbPoints.y; i++) {
        zMatrix[i] = new Float64Array(nbPoints.x);
      }

      return zMatrix;
    }

    function hasProperty(data, key) {
      return key in data;
    }

    const {
      parse: parse$7,
      stringify: stringify$7
    } = JSON;
    /**
     * convert width and fwhm to ppm
     */

    function convertWidth(peaks, options) {
      const {
        frequency,
        convertTo,
        output = parse$7(stringify$7(peaks))
      } = options;
      const convert = getConverter(convertTo, frequency);

      for (const peak of output) {
        peak.width = convert(peak.width);

        if (hasProperty(peak, 'shape')) {
          const shape = peak.shape;

          if (shape.fwhm) {
            shape.fwhm = convert(shape.fwhm);
          }
        }
      }

      return output;
    }

    function getConverter(convertTo, frequency) {
      switch (convertTo) {
        case 'ppm':
          return x => x / frequency;

        case 'hz':
          return x => x * frequency;

        default:
          throw new Error(`Does not support convert to ${convertTo}`);
      }
    }

    function convertWidthToPPM(peaks, options) {
      return convertWidth(peaks, { ...options,
        convertTo: 'ppm'
      });
    }

    function peaksToXY(peaks, options) {
      const {
        frequency,
        nbPoints = 1024,
        shape
      } = options;

      if (!frequency) {
        throw new Error('frequency is mandatory');
      }

      const newPeaks = convertWidthToPPM(peaks, {
        frequency
      });
      return generateSpectrum(newPeaks, {
        generator: { ...getFromTo$1(newPeaks, options),
          nbPoints,
          shape
        }
      });
    }

    function getFromTo$1(newPeaks, options) {
      if ('to' in options && 'from' in options) {
        return {
          from: options.from,
          to: options.to
        };
      }

      newPeaks.sort((a, b) => a.x - b.x);
      const firstPeak = newPeaks[0];
      const lastPeak = newPeaks[newPeaks.length - 1];
      const {
        from = firstPeak.x - firstPeak.width * 2 / options.frequency,
        to = lastPeak.x + lastPeak.width * 2 / options.frequency
      } = options;
      return {
        from,
        to
      };
    }

    var IDX = 256,
        HEX = [],
        BUFFER;

    while (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);

    function v4() {
      var i = 0,
          num,
          out = '';

      if (!BUFFER || IDX + 16 > 256) {
        BUFFER = Array(i = 256);

        while (i--) BUFFER[i] = 256 * Math.random() | 0;

        i = IDX = 0;
      }

      for (; i < 16; i++) {
        num = BUFFER[IDX + i];
        if (i == 6) out += HEX[num & 15 | 64];else if (i == 8) out += HEX[num & 63 | 128];else out += HEX[num];
        if (i & 1 && i > 1 && i < 11) out += '-';
      }

      IDX++;
      return out;
    }

    /**
     * Apply Savitzky Golay algorithm
     * @param [ys] Array of y values
     * @param [xs] Array of X or deltaX
     * @return  Array containing the new ys (same length)
     */

    function sgg(ys, xs) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      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 (!isAnyArray(ys)) {
        throw new TypeError('Y values must be an array');
      }

      if (typeof xs === 'undefined') {
        throw new TypeError('X must be defined');
      }

      if (windowSize > ys.length) {
        throw new RangeError(`Window size is higher than the data length ${windowSize}>${ys.length}`);
      }

      if (derivative < 0 || !Number.isInteger(derivative)) {
        throw new RangeError('Derivative should be a positive integer');
      }

      if (polynomial < 1 || !Number.isInteger(polynomial)) {
        throw new RangeError('Polynomial should be a positive integer');
      }

      if (polynomial >= 6) {
        // eslint-disable-next-line no-console
        console.warn('You should not use polynomial grade higher than 5 if you are' + ' not sure that your data arises from such a model. Possible polynomial oscillation problems');
      }

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

      if (isAnyArray(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++) {
        sum += (2 * k + 1) * (genFact(2 * m, k) / genFact(2 * m + k + 1, k + 1)) * gramPoly(i, m, k, 0) * gramPoly(t, m, k, s);
      }

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


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

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

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

      return weights;
    }

    /**
     * Correction of the x and y coordinates using a quadratic optimizations with the peak and its 3 closest neighbors to determine the true x,y values of the peak.
     * This process is done in place and is very fast.
     * @param data
     * @param peaks
     */
    function optimizeTop(data, peaks) {
      const {
        x,
        y
      } = data;

      for (const peak of peaks) {
        let currentIndex = peak.index; // The detected peak could be moved 1 or 2 units to left or right.

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


        if (y[currentIndex - 1] > 0 && y[currentIndex + 1] > 0 && y[currentIndex] >= y[currentIndex - 1] && y[currentIndex] >= y[currentIndex + 1] && (y[currentIndex] !== y[currentIndex - 1] || y[currentIndex] !== y[currentIndex + 1])) {
          let alpha = 20 * Math.log10(y[currentIndex - 1]);
          let beta = 20 * Math.log10(y[currentIndex]);
          let gamma = 20 * Math.log10(y[currentIndex + 1]);
          let p = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma);
          peak.x = x[currentIndex] + (x[currentIndex] - x[currentIndex - 1]) * p;
          peak.y = y[currentIndex] - 0.25 * (y[currentIndex - 1] - y[currentIndex + 1]) * p;
        }
      }
    }

    /**
     * Global spectra deconvolution
     * @param  data - Object data with x and y arrays. Values in x has to be growing
     * @param {number} [options.broadRatio = 0.00] - If `broadRatio` is higher than 0, then all the peaks which second derivative
     * smaller than `broadRatio * maxAbsSecondDerivative` will be marked with the soft mask equal to true.

     */

    function gsd(data) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        sgOptions = {
          windowSize: 9,
          polynomial: 3
        },
        noiseLevel,
        smoothY = false,
        maxCriteria = true,
        minMaxRatio = 0.00025,
        realTopDetection = false
      } = options;
      let {
        x,
        y
      } = data;

      if (!xIsMonotoneIncreasing(x)) {
        throw new Error('GSD only accepts monotone increasing x values');
      } //rescale;


      y = y.slice(); // If the max difference between delta x is less than 5%, then,
      // we can assume it to be equally spaced variable

      let equallySpaced = xIsEquallySpaced(x);

      if (noiseLevel === undefined) {
        if (equallySpaced) {
          const noiseInfo = xNoiseStandardDeviation(y);

          if (maxCriteria) {
            noiseLevel = noiseInfo.median + 1.5 * noiseInfo.sd;
          } else {
            noiseLevel = -noiseInfo.median + 1.5 * noiseInfo.sd;
          }
        } else {
          noiseLevel = 0;
        }
      } else {
        if (maxCriteria === false) {
          noiseLevel *= -1;
        }
      }

      if (maxCriteria === false) {
        for (let i = 0; i < y.length; i++) {
          y[i] *= -1;
        }
      }

      if (noiseLevel !== undefined) {
        for (let i = 0; i < y.length; i++) {
          if (y[i] < noiseLevel) {
            y[i] = noiseLevel;
          }
        }
      }

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

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

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

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

      const minY = xMinValue(yData);
      const maxY = xMaxValue(yData);
      if (minY > maxY || minY === maxY) return [];
      const yThreshold = minY + (maxY - minY) * minMaxRatio;
      const dX = x[1] - x[0];
      let lastMax = null;
      let lastMin = null;
      let minddY = [];
      let intervalL = [];
      let intervalR = []; // By the intermediate value theorem We cannot find 2 consecutive maximum or minimum

      for (let i = 1; i < yData.length - 1; ++i) {
        if (dY[i] < dY[i - 1] && dY[i] <= dY[i + 1] || dY[i] <= dY[i - 1] && dY[i] < dY[i + 1]) {
          lastMin = {
            x: x[i],
            index: i
          };

          if (dX > 0 && lastMax !== null) {
            intervalL.push(lastMax);
            intervalR.push(lastMin);
          }
        } // Maximum in first derivative


        if (dY[i] >= dY[i - 1] && dY[i] > dY[i + 1] || dY[i] > dY[i - 1] && dY[i] >= dY[i + 1]) {
          lastMax = {
            x: x[i],
            index: i
          };

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


        if (ddY[i] < ddY[i - 1] && ddY[i] < ddY[i + 1]) {
          minddY.push(i);
        }
      }

      let lastK = -1;
      const peaks = [];

      for (const minddYIndex of minddY) {
        let deltaX = x[minddYIndex];
        let possible = -1;
        let k = lastK + 1;
        let minDistance = Number.POSITIVE_INFINITY;
        let currentDistance = 0;

        while (possible === -1 && k < intervalL.length) {
          currentDistance = Math.abs(deltaX - (intervalL[k].x + intervalR[k].x) / 2);

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

          ++k; // Not getting closer?

          if (currentDistance >= minDistance) {
            break;
          }

          minDistance = currentDistance;
        }

        if (possible !== -1) {
          if (yData[minddYIndex] > yThreshold) {
            let width = Math.abs(intervalR[possible].x - intervalL[possible].x);
            peaks.push({
              id: v4(),
              x: deltaX,
              y: yData[minddYIndex],
              width,
              index: minddYIndex,
              ddY: ddY[minddYIndex],
              inflectionPoints: {
                from: intervalL[possible],
                to: intervalR[possible]
              }
            });
          }
        }
      }

      if (realTopDetection) {
        optimizeTop({
          x,
          y: yData
        }, peaks);
      }

      peaks.forEach(peak => {
        if (!maxCriteria) {
          peak.y *= -1;
          peak.ddY = peak.ddY * -1;
        }
      });
      peaks.sort((a, b) => {
        return a.x - b.x;
      });
      return peaks;
    }

    /**
     * This function returns the sumOfShapes function
     * This function gives sumOfShapes access to the peak list and the associated data
     * @param parameters - parameters
     */
    function getSumOfShapes$1(internalPeaks) {
      return function sumOfShapes(parameters) {
        return x => {
          let totalY = 0;

          for (const peak of internalPeaks) {
            const peakX = parameters[peak.fromIndex];
            const y = parameters[peak.fromIndex + 1];

            for (let i = 2; i <= peak.toIndex; i++) {
              //@ts-expect-error Not simply to solve the issue
              peak.shapeFct[peak.parameters[i]] = parameters[peak.fromIndex + i];
            }

            totalY += y * peak.shapeFct.fct(x - peakX);
          }

          return totalY;
        };
      };
    }

    /**
     * Asserts that value is truthy.
     *
     * @param value - Value to check.
     * @param message - Optional error message to throw.
     */
    function assert(value, message) {
      if (!value) {
        throw new Error(message ? message : 'unreachable');
      }
    }

    const DefaultParameters = {
      x: {
        init: peak => peak.x,
        min: (peak, peakShape) => peak.x - peakShape.fwhm * 2,
        max: (peak, peakShape) => peak.x + peakShape.fwhm * 2,
        gradientDifference: (peak, peakShape) => peakShape.fwhm * 2e-3
      },
      y: {
        init: peak => peak.y,
        min: peak => peak.y < 0 ? -1.1 : 0,
        max: peak => peak.y < 0 ? 0 : 1.1,
        gradientDifference: () => 1e-3
      },
      fwhm: {
        init: (peak, peakShape) => peakShape.fwhm,
        min: (peak, peakShape) => peakShape.fwhm * 0.25,
        max: (peak, peakShape) => peakShape.fwhm * 4,
        gradientDifference: (peak, peakShape) => peakShape.fwhm * 2e-3
      },
      mu: {
        init: (peak, peakShape) => peakShape.mu,
        min: () => 0,
        max: () => 1,
        gradientDifference: () => 0.01
      }
    };

    const properties$1 = ['init', 'min', 'max', 'gradientDifference'];
    /**
     * Return an array of internalPeaks that contains the exact init, min, max values based on the options
     * @param peaks
     * @param options
     * @returns
     */

    function getInternalPeaks(peaks, minMaxY) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      let index = 0;
      let internalPeaks = [];
      const {
        baseline: shiftValue = minMaxY.min
      } = options;
      const normalizedPeaks = peaks.map(peak => {
        return { ...peak,
          y: (peak.y - shiftValue) / minMaxY.range
        };
      });

      for (const peak of normalizedPeaks) {
        const {
          id,
          shape = options.shape ? options.shape : {
            kind: 'gaussian'
          }
        } = peak;
        const shapeFct = getShape1D(shape);
        const parameters = ['x', 'y', ...shapeFct.getParameters()];
        const propertiesValues = {
          min: [],
          max: [],
          init: [],
          gradientDifference: []
        };

        for (let parameter of parameters) {
          for (let property of properties$1) {
            // check if the property is specified in the peak
            let propertyValue = peak?.parameters?.[parameter]?.[property];

            if (propertyValue) {
              propertyValue = getNormalizedValue$1(propertyValue, parameter, property, minMaxY, options.baseline);
              propertiesValues[property].push(propertyValue);
              continue;
            } // check if there are some global option, it could be a number or a callback


            let generalParameterValue = options?.parameters?.[parameter]?.[property];

            if (generalParameterValue) {
              if (typeof generalParameterValue === 'number') {
                generalParameterValue = getNormalizedValue$1(generalParameterValue, parameter, property, minMaxY, options.baseline);
                propertiesValues[property].push(generalParameterValue);
                continue;
              } else {
                let value = generalParameterValue(peak);
                value = getNormalizedValue$1(value, parameter, property, minMaxY, options.baseline);
                propertiesValues[property].push(value);
                continue;
              }
            } // we just need to take the default parameters


            assert(DefaultParameters[parameter], `No default parameter for ${parameter}`);
            const defaultParameterValues = DefaultParameters[parameter][property]; //@ts-expect-error should never happen

            propertiesValues[property].push(defaultParameterValues(peak, shapeFct));
          }
        }

        const fromIndex = index;
        const toIndex = fromIndex + parameters.length - 1;
        index += toIndex - fromIndex + 1;
        internalPeaks.push({
          id,
          shape,
          shapeFct,
          parameters,
          propertiesValues,
          fromIndex,
          toIndex
        });
      }

      return internalPeaks;
    }

    function getNormalizedValue$1(value, parameter, property, minMaxY, baseline) {
      if (parameter === 'y') {
        if (property === 'gradientDifference') {
          return value;
        } else {
          return baseline !== undefined ? (value - baseline) / minMaxY.range : (value - minMaxY.min) / minMaxY.range;
        }
      }

      return value;
    }

    function checkOptions(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(data.x) || data.x.length < 2 || !isAnyArray(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(parameters)) {
        throw new Error('initialValues must be an array');
      }

      if (typeof gradientDifference === 'number') {
        gradientDifference = new Array(parameters.length).fill(gradientDifference);
      } else if (isAnyArray(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(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:ArrayLike<number>, y:ArrayLike<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
     * @param {ArrayLike<number>} parameters - Array of current parameter values
     * @param {function} parameterizedFunction - The parameters and returns a function with the independent variable as a parameter
     * @param {ArrayLike<number>} 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;
    }

    /**
     * Difference of the matrix function over the parameters
     * @ignore
     * @param {{x:ArrayLike<number>, y:ArrayLike<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
     * @param {ArrayLike<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.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:ArrayLike<number>, y:ArrayLike<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
     * @param {ArrayLike<number>} evaluatedData - Array of previous evaluated function values
     * @return {Matrix}
     */

    function matrixFunction(data, evaluatedData) {
      const m = data.x.length;
      let ans = new Matrix(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:ArrayLike<number>, y:ArrayLike<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
     */


    function step(data, params, damping, gradientDifference, parameterizedFunction, centralDifference, weights) {
      let value = damping;
      let identity = Matrix.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 jacobianWeightResidualError = gradientFunc.mmul(residualError.scale('row', {
        scale: weights
      }));
      let perturbations = inverseMatrix.mmul(jacobianWeightResidualError);
      return {
        perturbations,
        jacobianWeightResidualError
      };
    }

    /**
     * Curve fitting algorithm
     * @param {{x:ArrayLike<number>, y:ArrayLike<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|ArrayLike<number>} [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|ArrayLike<number>} [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 {ArrayLike<number>} [options.minValues] - Minimum allowed values for parameters
     * @param {ArrayLike<number>} [options.maxValues] - Maximum allowed values for parameters
     * @param {ArrayLike<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) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      let {
        checkTimeout,
        minValues,
        maxValues,
        parameters,
        weightSquare,
        damping,
        dampingStepUp,
        dampingStepDown,
        maxIterations,
        errorTolerance,
        centralDifference,
        gradientDifference,
        improvementThreshold
      } = checkOptions(data, parameterizedFunction, options);
      let error = errorCalculation(data, parameters, parameterizedFunction, weightSquare);
      let optimalError = error;
      let optimalParameters = parameters.slice();
      let converged = error <= errorTolerance;
      let iteration = 0;

      for (; iteration < maxIterations && !converged; iteration++) {
        let previousError = error;
        let {
          perturbations,
          jacobianWeightResidualError
        } = 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;

        if (error < optimalError - errorTolerance) {
          optimalError = error;
          optimalParameters = parameters.slice();
        }

        let improvementMetric = (previousError - error) / perturbations.transpose().mmul(perturbations.mul(damping).add(jacobianWeightResidualError)).get(0, 0);

        if (improvementMetric > improvementThreshold) {
          damping = Math.max(damping / dampingStepDown, 1e-7);
        } else {
          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: optimalParameters,
        parameterError: optimalError,
        iterations: iteration
      };
    }

    /** Algorithm to select the method.
     * @param optimizationOptions - Optimization options
     * @returns - The algorithm and optimization options
     */

    function selectMethod() {
      let optimizationOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let {
        kind = 'lm',
        options
      } = optimizationOptions;

      switch (kind) {
        case 'lm':
        case 'levenbergMarquardt':
          return {
            algorithm: levenbergMarquardt,
            optimizationOptions: {
              damping: 1.5,
              maxIterations: 100,
              errorTolerance: 1e-8,
              ...options
            }
          };

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

    /**
     * Fits a set of points to the sum of a set of bell functions.
     *
     * @param data - An object containing the x and y data to be fitted.
     * @param peaks - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
     * @param options - Options for optimize
     * @returns - An 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, peaks) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      // rescale data
      let temp = xMinMaxValues(data.y);
      const minMaxY = { ...temp,
        range: temp.max - temp.min
      };
      const internalPeaks = getInternalPeaks(peaks, minMaxY, options); // need to rescale what is related to Y

      const {
        baseline: shiftValue = minMaxY.min
      } = options;
      let normalizedY = new Float64Array(data.y.length);

      for (let i = 0; i < data.y.length; i++) {
        normalizedY[i] = (data.y[i] - shiftValue) / minMaxY.range;
      }

      const nbParams = internalPeaks[internalPeaks.length - 1].toIndex + 1;
      const minValues = new Float64Array(nbParams);
      const maxValues = new Float64Array(nbParams);
      const initialValues = new Float64Array(nbParams);
      const gradientDifferences = new Float64Array(nbParams);
      let index = 0;

      for (const peak of internalPeaks) {
        for (let i = 0; i < peak.parameters.length; i++) {
          minValues[index] = peak.propertiesValues.min[i];
          maxValues[index] = peak.propertiesValues.max[i];
          initialValues[index] = peak.propertiesValues.init[i];
          gradientDifferences[index] = peak.propertiesValues.gradientDifference[i];
          index++;
        }
      }

      let {
        algorithm,
        optimizationOptions
      } = selectMethod(options.optimization);
      let sumOfShapes = getSumOfShapes$1(internalPeaks);
      let fitted = algorithm({
        x: data.x,
        y: normalizedY
      }, sumOfShapes, {
        minValues,
        maxValues,
        initialValues,
        gradientDifference: gradientDifferences,
        ...optimizationOptions
      });
      const fittedValues = fitted.parameterValues;
      let newPeaks = [];

      for (let peak of internalPeaks) {
        const {
          id,
          shape,
          parameters,
          fromIndex
        } = peak;
        let newPeak = {
          x: 0,
          y: 0,
          shape
        };

        if (id) {
          newPeak = { ...newPeak,
            id
          };
        }

        newPeak.x = fittedValues[fromIndex];
        newPeak.y = fittedValues[fromIndex + 1] * minMaxY.range + shiftValue;

        for (let i = 2; i < parameters.length; i++) {
          //@ts-expect-error should be fixed once
          newPeak.shape[parameters[i]] = fittedValues[fromIndex + i];
        }

        newPeaks.push(newPeak);
      }

      return {
        error: fitted.parameterError,
        iterations: fitted.iterations,
        peaks: newPeaks
      };
    }

    const {
      parse: parse$6,
      stringify: stringify$6
    } = JSON;
    /**
     * add missing property if it does not exist in the peak,
     * if shape exists but fwhm doesn't, it will be calculated from peak.width
     */

    function addMissingShape(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        shape = {
          kind: 'gaussian'
        },
        output = parse$6(stringify$6(peaks))
      } = options;
      let shapeInstance = getShape1D(shape);
      return output.map(peak => {
        if (hasShape(peak)) {
          if (!('fwhm' in peak.shape)) {
            const shapeInstance = getShape1D(peak.shape);
            peak.shape.fwhm = shapeInstance.widthToFWHM(peak.width);
          }

          return peak;
        }

        return { ...peak,
          shape: {
            fwhm: shapeInstance.widthToFWHM(peak.width),
            ...shape
          }
        };
      });
    }

    function hasShape(peak) {
      return 'shape' in peak;
    }

    /**
     * Group peaks based on factor
     * In order to group peaks we only need the x and width value. This means that
     * in the current implementation we don't take into account the asymmetry of peaks
     */
    function groupPeaks(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      if (peaks && peaks.length === 0) return [];
      const {
        factor = 1
      } = options;
      peaks = JSON.parse(JSON.stringify(peaks));
      peaks.sort((a, b) => a.x - b.x);
      let previousPeak = peaks[0];
      let currentGroup = [previousPeak];
      let groups = [currentGroup];

      for (let i = 1; i < peaks.length; i++) {
        const peak = peaks[i];

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

        previousPeak = peak;
      }

      return groups;
    }

    /**
     * Optimize the position (x), max intensity (y), full width at half maximum (fwhm)
     * and the ratio of gaussian contribution (mu) if it's required. It currently supports three kind of shapes: gaussian, lorentzian and pseudovoigt
     * @param data - An object containing the x and y data to be fitted.
     * @param peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
     */

    function optimizePeaksWithLogs(data, peakList) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      const {
        fromTo = {},
        baseline,
        shape = {
          kind: 'gaussian'
        },
        groupingFactor = 1,
        factorLimits = 2,
        optimization = {
          kind: 'lm',
          options: {
            timeout: 10
          }
        }
      } = options;
      /*
      The optimization algorithm will take some group of peaks.
      We can not simply optimize everything because there would be too many variables to optimize
      and it would be too time consuming.
      */

      let groups = groupPeaks(peakList, {
        factor: groupingFactor
      });
      let logs = [];
      let results = [];
      groups.forEach(peakGroup => {
        const start = Date.now(); // In order to make optimization we will add fwhm and shape on all the peaks

        const peaks = addMissingShape(peakGroup, {
          shape
        });
        const firstPeak = peaks[0];
        const lastPeak = peaks[peaks.length - 1];
        const {
          from = firstPeak.x - firstPeak.width * factorLimits,
          to = lastPeak.x + lastPeak.width * factorLimits
        } = fromTo;
        const {
          fromIndex,
          toIndex
        } = xGetFromToIndex(data.x, {
          from,
          to
        });
        const x = data.x instanceof Float64Array ? data.x.subarray(fromIndex, toIndex) : data.x.slice(fromIndex, toIndex);
        const y = data.y instanceof Float64Array ? data.y.subarray(fromIndex, toIndex) : data.y.slice(fromIndex, toIndex);
        const log = {
          range: {
            from,
            to
          },
          parameters: optimization,
          groupSize: peakGroup.length,
          time: Date.now() - start
        };

        if (x.length > 5) {
          const {
            iterations,
            error,
            peaks: optimizedPeaks
          } = optimize({
            x,
            y
          }, peaks, {
            shape,
            baseline,
            optimization
          });

          for (let i = 0; i < peaks.length; i++) {
            results.push({ ...optimizedPeaks[i],
              width: getShape1D(peaks[i].shape).fwhmToWidth(optimizedPeaks[i].shape.fwhm)
            });
          }

          logs.push({ ...log,
            iterations,
            error,
            message: 'optimization successful'
          });
        } else {
          results.push(...peaks);
          logs.push({ ...log,
            iterations: 0,
            message: 'x length too small for optimization'
          });
        }
      });
      return {
        logs,
        optimizedPeaks: results
      };
    }

    /**
     * Optimize the position (x), max intensity (y), full width at half maximum (fwhm)
     * and the ratio of gaussian contribution (mu) if it's required. It currently supports three kind of shapes: gaussian, lorentzian and pseudovoigt
     * @param data - An object containing the x and y data to be fitted.
     * @param peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
     */

    function optimizePeaks(data, peakList) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      return optimizePeaksWithLogs(data, peakList, options).optimizedPeaks;
    }

    const {
      parse: parse$5,
      stringify: stringify$5
    } = JSON;
    function addMissingIDs$1(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        output = parse$5(stringify$5(peaks))
      } = options;

      for (const peak of output) {
        if (!('id' in peak)) {
          peak.id = v4();
        }
      }

      return output;
    }

    function joinBroadPeaks(peakList) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        shape = {
          kind: 'gaussian'
        },
        optimization = {
          kind: 'lm',
          options: {
            timeout: 10
          }
        },
        broadWidth = 0.25,
        broadRatio = 0.0025
      } = options;
      let max = 0;
      let maxI = 0;
      let count = 1;
      const broadLines = [];

      if (peakList.length < 2) {
        return addMissingIDs$1(addMissingShape(peakList.map(getGSDPeakOptimizedStructure), {
          shape
        }));
      }

      let maxDdy = peakList[0].ddY;

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

      const newPeaks = [];

      for (const peak of peakList) {
        if (Math.abs(peak.ddY) <= broadRatio * maxDdy) {
          broadLines.push(peak);
        } else {
          newPeaks.push(getGSDPeakOptimizedStructure(peak));
        }
      } //@ts-expect-error Push a feke peak


      broadLines.push({
        x: Number.MAX_VALUE,
        y: 0
      });
      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) < broadWidth) {
          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 = optimizePeaks(candidates, [{
              id: v4(),
              x: broadLines[maxI].x,
              y: max,
              width: candidates.x[0] - candidates.x[candidates.x.length - 1]
            }], {
              shape,
              optimization
            });
            newPeaks.push(fitted[0]);
          } else {
            // Put back the candidates to the peak list
            for (const index of indexes) {
              newPeaks.push(getGSDPeakOptimizedStructure(broadLines[index]));
            }
          }

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

      newPeaks.sort((a, b) => {
        return a.x - b.x;
      });
      return addMissingIDs$1(newPeaks, {
        output: newPeaks
      });
    }

    function getGSDPeakOptimizedStructure(peak) {
      const {
        id,
        shape,
        x,
        y,
        width
      } = peak;
      let newPeak = {
        x,
        y,
        width,
        shape
      };
      if (id) newPeak.id = id;
      return newPeak;
    }

    const {
      parse: parse$4,
      stringify: stringify$4
    } = JSON;
    /**
     * Append 2 properties to the peaks, shape and fwhm
     */

    function setShape(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        shape = {
          kind: 'gaussian'
        },
        output = parse$4(stringify$4(peaks))
      } = options;
      let shapeInstance = getShape1D(shape);
      return output.map(peak => ({ ...peak,
        shape: {
          fwhm: shapeInstance.widthToFWHM(peak.width),
          ...shape
        }
      }));
    }

    function peakToXY(peak, options) {
      const newPeak = addMissingShape([peak])[0];
      const factor = getShape1D(newPeak.shape).getFactor();
      const {
        from = newPeak.x - peak.width * factor / options.frequency,
        to = newPeak.x + peak.width * factor / options.frequency
      } = options;
      return peaksToXY([peak], { ...options,
        from,
        to
      });
    }

    var browserPonyfill = {exports: {}};

    (function (module, exports) {
      var global = typeof self !== 'undefined' ? self : commonjsGlobal;

      var __self__ = function () {
        function F() {
          this.fetch = false;
          this.DOMException = global.DOMException;
        }

        F.prototype = global;
        return new F();
      }();

      (function (self) {
        (function (exports) {
          var support = {
            searchParams: 'URLSearchParams' in self,
            iterable: 'Symbol' in self && 'iterator' in Symbol,
            blob: 'FileReader' in self && 'Blob' in self && function () {
              try {
                new Blob();
                return true;
              } catch (e) {
                return false;
              }
            }(),
            formData: 'FormData' in self,
            arrayBuffer: 'ArrayBuffer' in self
          };

          function isDataView(obj) {
            return obj && DataView.prototype.isPrototypeOf(obj);
          }

          if (support.arrayBuffer) {
            var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];

            var isArrayBufferView = ArrayBuffer.isView || function (obj) {
              return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
            };
          }

          function normalizeName(name) {
            if (typeof name !== 'string') {
              name = String(name);
            }

            if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) {
              throw new TypeError('Invalid character in header field name');
            }

            return name.toLowerCase();
          }

          function normalizeValue(value) {
            if (typeof value !== 'string') {
              value = String(value);
            }

            return value;
          } // Build a destructive iterator for the value list


          function iteratorFor(items) {
            var iterator = {
              next: function () {
                var value = items.shift();
                return {
                  done: value === undefined,
                  value: value
                };
              }
            };

            if (support.iterable) {
              iterator[Symbol.iterator] = function () {
                return iterator;
              };
            }

            return iterator;
          }

          function Headers(headers) {
            this.map = {};

            if (headers instanceof Headers) {
              headers.forEach(function (value, name) {
                this.append(name, value);
              }, this);
            } else if (Array.isArray(headers)) {
              headers.forEach(function (header) {
                this.append(header[0], header[1]);
              }, this);
            } else if (headers) {
              Object.getOwnPropertyNames(headers).forEach(function (name) {
                this.append(name, headers[name]);
              }, this);
            }
          }

          Headers.prototype.append = function (name, value) {
            name = normalizeName(name);
            value = normalizeValue(value);
            var oldValue = this.map[name];
            this.map[name] = oldValue ? oldValue + ', ' + value : value;
          };

          Headers.prototype['delete'] = function (name) {
            delete this.map[normalizeName(name)];
          };

          Headers.prototype.get = function (name) {
            name = normalizeName(name);
            return this.has(name) ? this.map[name] : null;
          };

          Headers.prototype.has = function (name) {
            return this.map.hasOwnProperty(normalizeName(name));
          };

          Headers.prototype.set = function (name, value) {
            this.map[normalizeName(name)] = normalizeValue(value);
          };

          Headers.prototype.forEach = function (callback, thisArg) {
            for (var name in this.map) {
              if (this.map.hasOwnProperty(name)) {
                callback.call(thisArg, this.map[name], name, this);
              }
            }
          };

          Headers.prototype.keys = function () {
            var items = [];
            this.forEach(function (value, name) {
              items.push(name);
            });
            return iteratorFor(items);
          };

          Headers.prototype.values = function () {
            var items = [];
            this.forEach(function (value) {
              items.push(value);
            });
            return iteratorFor(items);
          };

          Headers.prototype.entries = function () {
            var items = [];
            this.forEach(function (value, name) {
              items.push([name, value]);
            });
            return iteratorFor(items);
          };

          if (support.iterable) {
            Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
          }

          function consumed(body) {
            if (body.bodyUsed) {
              return Promise.reject(new TypeError('Already read'));
            }

            body.bodyUsed = true;
          }

          function fileReaderReady(reader) {
            return new Promise(function (resolve, reject) {
              reader.onload = function () {
                resolve(reader.result);
              };

              reader.onerror = function () {
                reject(reader.error);
              };
            });
          }

          function readBlobAsArrayBuffer(blob) {
            var reader = new FileReader();
            var promise = fileReaderReady(reader);
            reader.readAsArrayBuffer(blob);
            return promise;
          }

          function readBlobAsText(blob) {
            var reader = new FileReader();
            var promise = fileReaderReady(reader);
            reader.readAsText(blob);
            return promise;
          }

          function readArrayBufferAsText(buf) {
            var view = new Uint8Array(buf);
            var chars = new Array(view.length);

            for (var i = 0; i < view.length; i++) {
              chars[i] = String.fromCharCode(view[i]);
            }

            return chars.join('');
          }

          function bufferClone(buf) {
            if (buf.slice) {
              return buf.slice(0);
            } else {
              var view = new Uint8Array(buf.byteLength);
              view.set(new Uint8Array(buf));
              return view.buffer;
            }
          }

          function Body() {
            this.bodyUsed = false;

            this._initBody = function (body) {
              this._bodyInit = body;

              if (!body) {
                this._bodyText = '';
              } else if (typeof body === 'string') {
                this._bodyText = body;
              } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
                this._bodyBlob = body;
              } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
                this._bodyFormData = body;
              } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
                this._bodyText = body.toString();
              } else if (support.arrayBuffer && support.blob && isDataView(body)) {
                this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.

                this._bodyInit = new Blob([this._bodyArrayBuffer]);
              } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
                this._bodyArrayBuffer = bufferClone(body);
              } else {
                this._bodyText = body = Object.prototype.toString.call(body);
              }

              if (!this.headers.get('content-type')) {
                if (typeof body === 'string') {
                  this.headers.set('content-type', 'text/plain;charset=UTF-8');
                } else if (this._bodyBlob && this._bodyBlob.type) {
                  this.headers.set('content-type', this._bodyBlob.type);
                } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
                  this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
                }
              }
            };

            if (support.blob) {
              this.blob = function () {
                var rejected = consumed(this);

                if (rejected) {
                  return rejected;
                }

                if (this._bodyBlob) {
                  return Promise.resolve(this._bodyBlob);
                } else if (this._bodyArrayBuffer) {
                  return Promise.resolve(new Blob([this._bodyArrayBuffer]));
                } else if (this._bodyFormData) {
                  throw new Error('could not read FormData body as blob');
                } else {
                  return Promise.resolve(new Blob([this._bodyText]));
                }
              };

              this.arrayBuffer = function () {
                if (this._bodyArrayBuffer) {
                  return consumed(this) || Promise.resolve(this._bodyArrayBuffer);
                } else {
                  return this.blob().then(readBlobAsArrayBuffer);
                }
              };
            }

            this.text = function () {
              var rejected = consumed(this);

              if (rejected) {
                return rejected;
              }

              if (this._bodyBlob) {
                return readBlobAsText(this._bodyBlob);
              } else if (this._bodyArrayBuffer) {
                return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
              } else if (this._bodyFormData) {
                throw new Error('could not read FormData body as text');
              } else {
                return Promise.resolve(this._bodyText);
              }
            };

            if (support.formData) {
              this.formData = function () {
                return this.text().then(decode);
              };
            }

            this.json = function () {
              return this.text().then(JSON.parse);
            };

            return this;
          } // HTTP methods whose capitalization should be normalized


          var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];

          function normalizeMethod(method) {
            var upcased = method.toUpperCase();
            return methods.indexOf(upcased) > -1 ? upcased : method;
          }

          function Request(input, options) {
            options = options || {};
            var body = options.body;

            if (input instanceof Request) {
              if (input.bodyUsed) {
                throw new TypeError('Already read');
              }

              this.url = input.url;
              this.credentials = input.credentials;

              if (!options.headers) {
                this.headers = new Headers(input.headers);
              }

              this.method = input.method;
              this.mode = input.mode;
              this.signal = input.signal;

              if (!body && input._bodyInit != null) {
                body = input._bodyInit;
                input.bodyUsed = true;
              }
            } else {
              this.url = String(input);
            }

            this.credentials = options.credentials || this.credentials || 'same-origin';

            if (options.headers || !this.headers) {
              this.headers = new Headers(options.headers);
            }

            this.method = normalizeMethod(options.method || this.method || 'GET');
            this.mode = options.mode || this.mode || null;
            this.signal = options.signal || this.signal;
            this.referrer = null;

            if ((this.method === 'GET' || this.method === 'HEAD') && body) {
              throw new TypeError('Body not allowed for GET or HEAD requests');
            }

            this._initBody(body);
          }

          Request.prototype.clone = function () {
            return new Request(this, {
              body: this._bodyInit
            });
          };

          function decode(body) {
            var form = new FormData();
            body.trim().split('&').forEach(function (bytes) {
              if (bytes) {
                var split = bytes.split('=');
                var name = split.shift().replace(/\+/g, ' ');
                var value = split.join('=').replace(/\+/g, ' ');
                form.append(decodeURIComponent(name), decodeURIComponent(value));
              }
            });
            return form;
          }

          function parseHeaders(rawHeaders) {
            var headers = new Headers(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
            // https://tools.ietf.org/html/rfc7230#section-3.2

            var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
            preProcessedHeaders.split(/\r?\n/).forEach(function (line) {
              var parts = line.split(':');
              var key = parts.shift().trim();

              if (key) {
                var value = parts.join(':').trim();
                headers.append(key, value);
              }
            });
            return headers;
          }

          Body.call(Request.prototype);

          function Response(bodyInit, options) {
            if (!options) {
              options = {};
            }

            this.type = 'default';
            this.status = options.status === undefined ? 200 : options.status;
            this.ok = this.status >= 200 && this.status < 300;
            this.statusText = 'statusText' in options ? options.statusText : 'OK';
            this.headers = new Headers(options.headers);
            this.url = options.url || '';

            this._initBody(bodyInit);
          }

          Body.call(Response.prototype);

          Response.prototype.clone = function () {
            return new Response(this._bodyInit, {
              status: this.status,
              statusText: this.statusText,
              headers: new Headers(this.headers),
              url: this.url
            });
          };

          Response.error = function () {
            var response = new Response(null, {
              status: 0,
              statusText: ''
            });
            response.type = 'error';
            return response;
          };

          var redirectStatuses = [301, 302, 303, 307, 308];

          Response.redirect = function (url, status) {
            if (redirectStatuses.indexOf(status) === -1) {
              throw new RangeError('Invalid status code');
            }

            return new Response(null, {
              status: status,
              headers: {
                location: url
              }
            });
          };

          exports.DOMException = self.DOMException;

          try {
            new exports.DOMException();
          } catch (err) {
            exports.DOMException = function (message, name) {
              this.message = message;
              this.name = name;
              var error = Error(message);
              this.stack = error.stack;
            };

            exports.DOMException.prototype = Object.create(Error.prototype);
            exports.DOMException.prototype.constructor = exports.DOMException;
          }

          function fetch(input, init) {
            return new Promise(function (resolve, reject) {
              var request = new Request(input, init);

              if (request.signal && request.signal.aborted) {
                return reject(new exports.DOMException('Aborted', 'AbortError'));
              }

              var xhr = new XMLHttpRequest();

              function abortXhr() {
                xhr.abort();
              }

              xhr.onload = function () {
                var options = {
                  status: xhr.status,
                  statusText: xhr.statusText,
                  headers: parseHeaders(xhr.getAllResponseHeaders() || '')
                };
                options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
                var body = 'response' in xhr ? xhr.response : xhr.responseText;
                resolve(new Response(body, options));
              };

              xhr.onerror = function () {
                reject(new TypeError('Network request failed'));
              };

              xhr.ontimeout = function () {
                reject(new TypeError('Network request failed'));
              };

              xhr.onabort = function () {
                reject(new exports.DOMException('Aborted', 'AbortError'));
              };

              xhr.open(request.method, request.url, true);

              if (request.credentials === 'include') {
                xhr.withCredentials = true;
              } else if (request.credentials === 'omit') {
                xhr.withCredentials = false;
              }

              if ('responseType' in xhr && support.blob) {
                xhr.responseType = 'blob';
              }

              request.headers.forEach(function (value, name) {
                xhr.setRequestHeader(name, value);
              });

              if (request.signal) {
                request.signal.addEventListener('abort', abortXhr);

                xhr.onreadystatechange = function () {
                  // DONE (success or failure)
                  if (xhr.readyState === 4) {
                    request.signal.removeEventListener('abort', abortXhr);
                  }
                };
              }

              xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
            });
          }

          fetch.polyfill = true;

          if (!self.fetch) {
            self.fetch = fetch;
            self.Headers = Headers;
            self.Request = Request;
            self.Response = Response;
          }

          exports.Headers = Headers;
          exports.Request = Request;
          exports.Response = Response;
          exports.fetch = fetch;
          Object.defineProperty(exports, '__esModule', {
            value: true
          });
          return exports;
        })({});
      })(__self__);

      __self__.fetch.ponyfill = true; // Remove "polyfill" property added by whatwg-fetch

      delete __self__.fetch.polyfill; // Choose between native implementation (global) or custom implementation (__self__)
      // var ctx = global.fetch ? global : __self__;

      var ctx = __self__; // this line disable service worker support temporarily

      exports = ctx.fetch; // To enable: import fetch from 'cross-fetch'

      exports.default = ctx.fetch; // For TypeScript consumers without esModuleInterop.

      exports.fetch = ctx.fetch; // To enable: import {fetch} from 'cross-fetch'

      exports.Headers = ctx.Headers;
      exports.Request = ctx.Request;
      exports.Response = ctx.Response;
      module.exports = exports;
    })(browserPonyfill, browserPonyfill.exports);

    var fetch = /*@__PURE__*/getDefaultExportFromCjs(browserPonyfill.exports);

    /* eslint-env browser */
    var browser = typeof self == 'object' ? self.FormData : window.FormData;
    var FormData$1 = browser;

    let xAtomicNumber = 0;
    /**
     * Tag an atom to be able to visualize it
     * @param {OCL.Molecule} molecule
     * @param {number} iAtom
     */

    function tagAtom(molecule, iAtom) {
      let customLabel = `${molecule.getAtomLabel(iAtom)}*`;
      molecule.setAtomCustomLabel(iAtom, customLabel);

      if (molecule.getAtomicNo(iAtom) === 1) {
        molecule.setAtomicNo(iAtom, getXAtomicNumber(molecule));
      } else {
        // we can not use X because we would have problems with valencies if it is
        // expanded hydrogens or not
        // we can not only use a custom label because it does not count for the canonisation
        molecule.setAtomMass(iAtom, molecule.getAtomMass(iAtom) + 5);
      }

      return customLabel;
    }

    function getXAtomicNumber(molecule) {
      if (!xAtomicNumber) {
        const OCL = molecule.getOCL();
        xAtomicNumber = OCL.Molecule.getAtomicNoFromLabel('X');
      }

      return xAtomicNumber;
    }

    /**
     * Add either missing chirality of diastereotopic missing chirality
     * The problem is that sometimes we need to add chiral bond that was not planned because it is the same group
     * This is the case for example for the valine where the 2 C of the methyl groups are diastereotopic
     * @param {OCL.Molecule} molecule
     * @param {object} [options={}]
     * @param {number} [options.esrType=cESRTypeAnd]
     */

    function addDiastereotopicMissingChirality(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        Molecule
      } = molecule.getOCL();
      const {
        esrType = Molecule.cESRTypeAnd
      } = options;

      for (let iAtom = 0; iAtom < molecule.getAllAtoms(); iAtom++) {
        let tempMolecule = molecule.getCompactCopy();
        tagAtom(tempMolecule, iAtom); // After copy, helpers must be recalculated

        tempMolecule.ensureHelperArrays(Molecule.cHelperBitsStereo); // We need to have >0 and not >1 because there could be unspecified chirality in racemate

        for (let i = 0; i < tempMolecule.getAtoms(); i++) {
          // changed from from handling below; TLS 9.Nov.2015
          if (tempMolecule.isAtomStereoCenter(i) && tempMolecule.getStereoBond(i) === -1) {
            let stereoBond = tempMolecule.getAtomPreferredStereoBond(i);

            if (stereoBond !== -1) {
              molecule.setBondType(stereoBond, Molecule.cBondTypeUp);

              if (molecule.getBondAtom(1, stereoBond) === i) {
                let connAtom = molecule.getBondAtom(0, stereoBond);
                molecule.setBondAtom(0, stereoBond, i);
                molecule.setBondAtom(1, stereoBond, connAtom);
              } // To me it seems that we have to add all stereo centers into AND group 0. TLS 9.Nov.2015


              molecule.setAtomESR(i, esrType, 0);
            }
          }
        }
      }
    }

    /**
     *
     * @param {OCL.Molecule} [molecule] An instance of a molecule
     * @param {object} [options={}]
     * @param {object} [options.OCL] openchemlib library
     */
    function makeRacemic(molecule) {
      const {
        Molecule
      } = molecule.getOCL(); // if we don't calculate this we have 2 epimers

      molecule.ensureHelperArrays(Molecule.cHelperCIP); // we need to make one group "AND" for chiral (to force to racemic, this means diastereotopic and not enantiotopic)

      for (let i = 0; i < molecule.getAllAtoms(); i++) {
        if (molecule.getAtomParity(i) !== Molecule.cAtomParityNone) {
          molecule.setAtomESR(i, Molecule.cESRTypeAnd, 0); // changed to group 0; TLS 9.Nov.2015
        }
      }
    }

    /**
     * Returns an array of diastereotopic ID (as oclCode)
     * @param {OCL.Molecule} molecule
     */

    function getDiastereotopicAtomIDs(molecule) {
      const OCL = molecule.getOCL();
      addDiastereotopicMissingChirality(molecule);
      let numberAtoms = molecule.getAllAtoms();
      let ids = [];

      for (let iAtom = 0; iAtom < numberAtoms; iAtom++) {
        let tempMolecule = molecule.getCompactCopy();
        tagAtom(tempMolecule, iAtom);
        makeRacemic(tempMolecule); // We need to ensure the helper array in order to get correctly the result of racemisation

        ids[iAtom] = tempMolecule.getCanonizedIDCode(OCL.Molecule.CANONIZER_ENCODE_ATOM_CUSTOM_LABELS);
      }

      return ids;
    }

    /**
     * This function groups the diasterotopic atomIds of the molecule based on equivalence of atoms. The output object contains
     * a set of chemically equivalent atoms(element.atoms) and the groups of magnetically equivalent atoms (element.magneticGroups)
     * @param {OCL.Molecule} molecule
     * @param {object} [options={}]
     * @param {string} [options.atomLabel] Select atoms of the given atomLabel. By default it returns all the explicit atoms in the molecule
     * @returns {Array}
     */

    function getGroupedDiastereotopicAtomIDs(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        atomLabel
      } = options;
      let diaIDs = getDiastereotopicAtomIDs(molecule);
      let diaIDsObject = {};

      for (let i = 0; i < diaIDs.length; i++) {
        if (!atomLabel || molecule.getAtomLabel(i) === atomLabel) {
          let diaID = diaIDs[i];

          if (!diaIDsObject[diaID]) {
            diaIDsObject[diaID] = {
              counter: 0,
              atoms: [],
              oclID: diaID,
              atomLabel: molecule.getAtomLabel(i)
            };
          }

          diaIDsObject[diaID].counter++;
          diaIDsObject[diaID].atoms.push(i);
        }
      }

      return Object.values(diaIDsObject);
    }

    /**
     * Check if a specific atom is a sp3 carbon
     * @param {OCL.Molecule} molecule
     * @param {number} atomID
     */
    function isCsp3(molecule, atomID) {
      if (molecule.getAtomicNo(atomID) !== 6) return false;
      if (molecule.getAtomCharge(atomID) !== 0) return false;

      if (molecule.getImplicitHydrogens(atomID) + molecule.getConnAtoms(atomID) !== 4) {
        return false;
      }

      return true;
    }

    const FULL_HOSE_CODE = 1;
    const HOSE_CODE_CUT_C_SP3_SP3 = 2;
    /**
     * Returns the hose code for a specific atom number
     * @param {OCL.Molecule} originalMolecule
     * @param {array<number>} rootAtoms
     * @param {object} [options={}]
     * @param {boolean} [options.isTagged] Specify is the atoms are already tagged
     * @param {number} [options.minSphereSize=0] Smallest hose code sphere
     * @param {number} [options.maxSphereSize=4] Largest hose code sphere
     * @param {number} [options.kind=FULL_HOSE_CODE] Kind of hose code, default usual sphere
     */

    function getHoseCodesForAtoms(originalMolecule) {
      let rootAtoms = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      const OCL = originalMolecule.getOCL();
      const {
        minSphereSize = 0,
        maxSphereSize = 4,
        kind = FULL_HOSE_CODE,
        isTagged = false
      } = options;
      const molecule = originalMolecule.getCompactCopy();

      if (!isTagged) {
        const tags = [];

        for (let i = 0; i < rootAtoms.length; i++) {
          let rootAtom = rootAtoms[i];
          tags.push(tagAtom(molecule, rootAtom));
          molecule.addImplicitHydrogens();
          molecule.addMissingChirality();
          molecule.ensureHelperArrays(OCL.Molecule.cHelperNeighbours); // because ensuring helper reorder atoms we need to look again for it
        }

        rootAtoms.length = 0;

        for (let j = 0; j < molecule.getAllAtoms(); j++) {
          if (tags.includes(molecule.getAtomCustomLabel(j))) {
            rootAtoms.push(j);
          }
        }
      }

      let fragment = new OCL.Molecule(0, 0);
      let results = [];
      let min = 0;
      let max = 0;
      let atomMask = new Array(molecule.getAllAtoms());
      let atomList = new Array(molecule.getAllAtoms());

      for (let sphere = 0; sphere <= maxSphereSize; sphere++) {
        if (max === 0) {
          for (let rootAtom of rootAtoms) {
            atomList[max] = rootAtom;
            atomMask[rootAtom] = true;
            max++;
          }
        } else {
          let newMax = max;

          for (let i = min; i < max; i++) {
            let atom = atomList[i];

            for (let j = 0; j < molecule.getAllConnAtoms(atom); j++) {
              let connAtom = molecule.getConnAtom(atom, j);

              if (!atomMask[connAtom]) {
                switch (kind) {
                  case FULL_HOSE_CODE:
                    atomMask[connAtom] = true;
                    atomList[newMax++] = connAtom;
                    break;

                  case HOSE_CODE_CUT_C_SP3_SP3:
                    if (!(isCsp3(molecule, atom) && isCsp3(molecule, connAtom))) {
                      atomMask[connAtom] = true;
                      atomList[newMax++] = connAtom;
                    }

                    break;

                  default:
                    throw new Error('getHoseCoesForAtom unknown kind');
                }
              }
            }
          }

          min = max;
          max = newMax;
        }

        molecule.copyMoleculeByAtoms(fragment, atomMask, true, null);

        if (sphere >= minSphereSize) {
          makeRacemic(fragment);
          results.push(fragment.getCanonizedIDCode(OCL.Molecule.CANONIZER_ENCODE_ATOM_CUSTOM_LABELS));
        }
      }

      return results;
    }

    /**
     * Returns the hose code for a specific atom number
     * @param {OCL.Molecule} originalMolecule
     * @param {number} rootAtom
     * @param {object} [options={}]
     * @param {boolean} [options.isTagged] Specify is the atom is already tagged
     * @param {number} [options.minSphereSize=0] Smallest hose code sphere
     * @param {number} [options.maxSphereSize=4] Largest hose code sphere
     * @param {number} [options.kind=FULL_HOSE_CODE] Kind of hose code, default usual sphere
     */

    function getHoseCodesForAtom(originalMolecule, rootAtom) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      return getHoseCodesForAtoms(originalMolecule, [rootAtom], options);
    }

    /**
     * Returns the hose code for a specific marked atom
     * @param {OCL.Molecule} diastereotopicID
     * @param {object} options
     */

    function getHoseCodesFromDiastereotopicID(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      molecule.addImplicitHydrogens();
      molecule.addMissingChirality(); // One of the atom has to be marked !

      let atomID = -1;

      for (let i = 0; i < molecule.getAllAtoms(); i++) {
        // we need to find the marked atom
        const atomCustomLabel = molecule.getAtomCustomLabel(i);

        if (atomCustomLabel != null && atomCustomLabel.endsWith('*')) {
          atomID = i;
          break;
        }
      }

      if (atomID >= 0) {
        options.isTagged = true;
        return getHoseCodesForAtom(molecule, atomID, options);
      }

      return undefined;
    }

    let fragment$1;
    /**
     * Returns the hose code for a specific atom number
     * @param {OCL.Molecule} molecule
     */

    function getHoseCodesForPath(molecule, from, to, maxLength) {
      const OCL = molecule.getOCL();
      const originalFrom = from;
      const originalTo = to;
      molecule = molecule.getCompactCopy();
      let originalAtoms = []; // path before renumbering

      molecule.getPath(originalAtoms, from, to, maxLength + 1);
      let torsion;

      if (originalAtoms.length === 4) {
        torsion = molecule.calculateTorsion(originalAtoms);
      }

      const tag1 = tagAtom(molecule, from);
      const tag2 = tagAtom(molecule, to);
      molecule.addImplicitHydrogens();
      molecule.addMissingChirality();
      molecule.ensureHelperArrays(OCL.Molecule.cHelperNeighbours);
      from = -1;
      to = -1;

      for (let i = 0; i < molecule.getAllAtoms(); i++) {
        if (tag1 === tag2) {
          if (molecule.getAtomCustomLabel(i) === tag1) {
            if (from === -1) {
              from = i;
            } else {
              to = i;
            }
          }
        } else {
          if (tag1 === molecule.getAtomCustomLabel(i)) {
            from = i;
          }

          if (tag2 === molecule.getAtomCustomLabel(i)) {
            to = i;
          }
        }
      }

      if (!fragment$1) fragment$1 = new OCL.Molecule(0, 0);
      let atoms = [];
      molecule.getPath(atoms, from, to, maxLength + 1);
      let min = 0;
      let max = 0;
      let atomMask = new Array(molecule.getAllAtoms()).fill(false);
      let atomList = new Array(molecule.getAllAtoms()).fill(-1);
      let hoses = [];

      for (let sphere = 0; sphere <= 2; sphere++) {
        if (max === 0) {
          for (let atom of atoms) {
            atomMask[atom] = true;
            atomList[max++] = atom;
          }
        } else {
          let newMax = max;

          for (let i = min; i < max; i++) {
            let atom = atomList[i];

            for (let j = 0; j < molecule.getAllConnAtoms(atom); j++) {
              let connAtom = molecule.getConnAtom(atom, j);

              if (!atomMask[connAtom]) {
                atomMask[connAtom] = true;
                atomList[newMax++] = connAtom;
              }
            }
          }

          min = max;
          max = newMax;
        }

        let atomMap = [];
        molecule.copyMoleculeByAtoms(fragment$1, atomMask, true, atomMap);
        makeRacemic(fragment$1);
        let oclID = fragment$1.getCanonizedIDCode(OCL.Molecule.CANONIZER_ENCODE_ATOM_CUSTOM_LABELS);
        hoses.push({
          sphere,
          oclID
        });
      }

      return {
        atoms: originalAtoms,
        from: originalFrom,
        to: originalTo,
        torsion,
        hoses,
        length: originalAtoms.length - 1
      };
    }

    /**
     * Returns various information about atoms in the molecule
     * @param {OCL.Molecule} [molecule]
     */

    function getAtomsInfo(molecule) {
      const OCL = molecule.getOCL();
      molecule.ensureHelperArrays(OCL.Molecule.cHelperRings);
      let diaIDs = getDiastereotopicAtomIDs(molecule);
      let results = [];

      for (let i = 0; i < diaIDs.length; i++) {
        let result = {
          oclID: diaIDs[i],
          extra: {
            singleBonds: 0,
            doubleBonds: 0,
            tripleBonds: 0,
            aromaticBonds: 0,
            cnoHybridation: 0 // should be 1 (sp), 2 (sp2) or 3 (sp3)

          }
        };
        let extra = result.extra;
        results.push(result);
        result.abnormalValence = molecule.getAtomAbnormalValence(i); // -1 is normal otherwise specified

        result.charge = molecule.getAtomCharge(i);
        result.cipParity = molecule.getAtomCIPParity(i);
        result.color = molecule.getAtomColor(i);
        result.customLabel = molecule.getAtomCustomLabel(i); //        result.esrGroup=molecule.getAtomESRGroup(i);
        //        result.esrType=molecule.getAtomESRType(i);

        result.atomicNo = molecule.getAtomicNo(i);
        result.label = molecule.getAtomLabel(i); //        result.list=molecule.getAtomList(i);
        //        result.listString=molecule.getAtomListString(i);
        //        result.mapNo=molecule.getAtomMapNo(i);

        result.mass = molecule.getAtomMass(i); //        result.parity=molecule.getAtomParity(i);
        //        result.pi=molecule.getAtomPi(i);
        //        result.preferredStereoBond=molecule.getAtomPreferredStereoBond(i);
        //        result.queryFeatures=molecule.getAtomQueryFeatures(i);

        result.radical = molecule.getAtomRadical(i);
        result.ringBondCount = molecule.getAtomRingBondCount(i); //        result.ringCount=molecule.getAtomRingCount(i);

        result.ringSize = molecule.getAtomRingSize(i);
        result.x = molecule.getAtomX(i);
        result.y = molecule.getAtomY(i);
        result.z = molecule.getAtomZ(i);
        result.allHydrogens = molecule.getAllHydrogens(i);
        result.connAtoms = molecule.getConnAtoms(i);
        result.allConnAtoms = molecule.getAllConnAtoms(i);
        result.implicitHydrogens = result.allHydrogens + result.connAtoms - result.allConnAtoms;
        result.isAromatic = molecule.isAromaticAtom(i);
        result.isAllylic = molecule.isAllylicAtom(i);
        result.isStereoCenter = molecule.isAtomStereoCenter(i);
        result.isRing = molecule.isRingAtom(i);
        result.isSmallRing = molecule.isSmallRingAtom(i);
        result.isStabilized = molecule.isStabilizedAtom(i); // todo HACK to circumvent bug in OCL that consider than an hydrogen is connected to itself

        result.extra.singleBonds = result.atomicNo === 1 ? 0 : result.implicitHydrogens;

        for (let j = 0; j < molecule.getAllConnAtoms(i); j++) {
          let bond = molecule.getConnBond(i, j);
          let bondOrder = molecule.getBondOrder(bond);

          if (molecule.isAromaticBond(bond)) {
            extra.aromaticBonds++;
          } else if (bondOrder === 1) {
            // not an hydrogen
            extra.singleBonds++;
          } else if (bondOrder === 2) {
            extra.doubleBonds++;
          } else if (bondOrder === 3) {
            extra.tripleBonds++;
          }
        }

        result.extra.totalBonds = result.extra.singleBonds + result.extra.doubleBonds + result.extra.tripleBonds + result.extra.aromaticBonds;

        if (result.atomicNo === 6) {
          result.extra.cnoHybridation = result.extra.totalBonds - 1;
        } else if (result.atomicNo === 7) {
          result.extra.cnoHybridation = result.extra.totalBonds;
        } else if (result.atomicNo === 8) {
          result.extra.cnoHybridation = result.extra.totalBonds + 1;
        } else if (result.atomicNo === 1) {
          let connectedAtom = molecule.getAllConnAtoms(i) === 0 ? 0 : molecule.getAtomicNo(molecule.getConnAtom(i, 0));
          result.extra.hydrogenOnAtomicNo = connectedAtom;

          if (connectedAtom === 7 || connectedAtom === 8) {
            result.extra.labileHydrogen = true;
          }
        }
      }

      return results;
    }

    /**
     * Algorithm that finds the shortest distance from one node to the other
     * @param {Matrix} adjMatrix - A squared adjacency matrix
     * @return {Matrix} - Distance from a node to the other, -1 if the node is unreachable
     */

    function floydWarshall(adjMatrix) {
      if (Matrix.isMatrix(adjMatrix) && adjMatrix.columns !== adjMatrix.rows) {
        throw new TypeError('The adjacency matrix should be squared');
      }

      const numVertices = adjMatrix.columns;
      let distMatrix = new Matrix(numVertices, numVertices);
      distMatrix.apply((row, column) => {
        // principal diagonal is 0
        if (row === column) {
          distMatrix.set(row, column, 0);
        } else {
          let val = adjMatrix.get(row, column);

          if (val || Object.is(val, -0)) {
            // edges values remain the same
            distMatrix.set(row, column, val);
          } else {
            // 0 values become infinity
            distMatrix.set(row, column, Number.POSITIVE_INFINITY);
          }
        }
      });

      for (let k = 0; k < numVertices; ++k) {
        for (let i = 0; i < numVertices; ++i) {
          for (let j = 0; j < numVertices; ++j) {
            let dist = distMatrix.get(i, k) + distMatrix.get(k, j);

            if (distMatrix.get(i, j) > dist) {
              distMatrix.set(i, j, dist);
            }
          }
        }
      } // When there's no connection the value is -1


      distMatrix.apply((row, column) => {
        if (distMatrix.get(row, column) === Number.POSITIVE_INFINITY) {
          distMatrix.set(row, column, -1);
        }
      });
      return distMatrix;
    }

    /**
     * Returns a connectivity matrix
     * @param {OCL.Molecule} molecule
     * @param {object} [options={}]
     * @param {boolean} [options.pathLength=false] get the path length between atoms
     * @param {boolean} [options.mass=false] set the nominal mass of the atoms on diagonal
     * @param {boolean} [options.atomicNo=false] set the atomic number of the atom on diagonal
     * @param {boolean} [options.negativeAtomicNo=false] set the atomic number * -1 of the atom on diagonal
     * @param {boolean} [options.sdt=false] set 1, 2 or 3 depending if single, double or triple bond
     * @param {boolean} [options.sdta=false] set 1, 2, 3 or 4 depending if single, double, triple or aromatic  bond
     */

    function getConnectivityMatrix(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const OCL = molecule.getOCL();
      molecule.ensureHelperArrays(OCL.Molecule.cHelperNeighbours);
      let nbAtoms = molecule.getAllAtoms();
      let result = new Array(nbAtoms).fill();
      result = result.map(() => new Array(nbAtoms).fill(0));

      if (!options.pathLength) {
        if (options.atomicNo) {
          for (let i = 0; i < nbAtoms; i++) {
            result[i][i] = molecule.getAtomicNo(i);
          }
        } else if (options.negativeAtomicNo) {
          for (let i = 0; i < nbAtoms; i++) {
            result[i][i] = -molecule.getAtomicNo(i);
          }
        } else if (options.mass) {
          for (let i = 0; i < nbAtoms; i++) {
            result[i][i] = OCL.Molecule.cRoundedMass[molecule.getAtomicNo(i)];
          }
        } else {
          for (let i = 0; i < nbAtoms; i++) {
            result[i][i] = 1;
          }
        }
      }

      if (options.sdt) {
        for (let i = 0; i < nbAtoms; i++) {
          let l = molecule.getAllConnAtoms(i);

          for (let j = 0; j < l; j++) {
            result[i][molecule.getConnAtom(i, j)] = molecule.getConnBondOrder(i, j);
          }
        }
      } else if (options.sdta) {
        for (let i = 0; i < nbAtoms; i++) {
          let l = molecule.getAllConnAtoms(i);

          for (let j = 0; j < l; j++) {
            let bondNumber = molecule.getConnBond(i, j);

            if (molecule.isAromaticBond(bondNumber)) {
              result[i][molecule.getConnAtom(i, j)] = 4;
            } else {
              result[i][molecule.getConnAtom(i, j)] = molecule.getConnBondOrder(i, j);
            }
          }
        }
      } else {
        for (let i = 0; i < nbAtoms; i++) {
          let l = molecule.getAllConnAtoms(i);

          for (let j = 0; j < l; j++) {
            result[i][molecule.getConnAtom(i, j)] = 1;
          }
        }
      }

      if (options.pathLength) {
        result = floydWarshall(new Matrix(result)).to2DArray();
      }

      return result;
    }

    /**
     * Calculates the path between 2 atoms
     * @param {OCL.Molecule} molecule
     * @param {number} from - index of the first atom
     * @param {number} to - index of the end atom
     * @param {number} maxLength - maximal length of the path
     */
    function getPathAndTorsion(molecule, from, to, maxLength) {
      let originalAtoms = []; // path before renumbering

      molecule.getPath(originalAtoms, from, to, maxLength + 1);
      let torsion;

      if (originalAtoms.length === 4) {
        torsion = molecule.calculateTorsion(originalAtoms);
      }

      return {
        atoms: originalAtoms,
        from,
        to,
        torsion,
        length: originalAtoms.length - 1
      };
    }

    let fragment;
    /**
     *
     * @param {OCL.Molecule} molecule
     * @param {object} [options={}]
     * @param {string} [options.fromLabel='H']
     * @param {string} [options.toLabel='H']
     * @param {number} [options.minLength=1]
     * @param {number} [options.maxLength=4]
     * @param {boolean} [options.withHOSES=false]

     */

    function getPathsInfo(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        fromLabel = 'H',
        toLabel = 'H',
        minLength = 1,
        maxLength = 4,
        withHOSES = false
      } = options;
      const OCL = molecule.getOCL();

      if (!fragment) {
        fragment = new OCL.Molecule(0, 0);
      }

      let fromAtomicNumber = OCL.Molecule.getAtomicNoFromLabel(fromLabel);
      let toAtomicNumber = OCL.Molecule.getAtomicNoFromLabel(toLabel); // we need to find all the atoms 'fromLabel' and 'toLabel'

      let atomsInfo = getAtomsInfo(molecule);
      let pathLengthMatrix = getConnectivityMatrix(molecule, {
        pathLength: true
      });

      for (let from = 0; from < molecule.getAllAtoms(); from++) {
        atomsInfo[from].paths = [];

        for (let to = 0; to < molecule.getAllAtoms(); to++) {
          if (from !== to) {
            if (molecule.getAtomicNo(from) === fromAtomicNumber) {
              if (molecule.getAtomicNo(to) === toAtomicNumber) {
                let pathLength = pathLengthMatrix[from][to];

                if (pathLength >= minLength && pathLength <= maxLength) {
                  if (withHOSES) {
                    atomsInfo[from].paths.push(getHoseCodesForPath(molecule, from, to, pathLength));
                  } else {
                    atomsInfo[from].paths.push(getPathAndTorsion(molecule, from, to, pathLength));
                  }
                }
              }
            }
          }
        }
      }

      return atomsInfo;
    }

    function sum(input) {
      if (!isAnyArray(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(input) / input.length;
    }

    const couplingValues = {
      s: 0,
      d: 1,
      t: 2,
      q: 3,
      quint: 4,
      h: 5,
      hex: 5,
      hept: 6,
      sept: 6,
      oct: 7,
      o: 7,
      non: 8,
      n: 8
    };

    function joinPatterns(patterns) {
      const sum = patterns.reduce((sum, pattern) => {
        if (isNaN(couplingValues[pattern])) {
          throw new Error(`pattern ${pattern} is not in ${Object.keys(couplingValues).join(' ')}`);
        }

        return sum + couplingValues[pattern];
      }, 0);

      if (!couplingPatterns[sum]) {
        throw new Error("The joined pattern doesn't exist");
      }

      return couplingPatterns[sum];
    }

    const localeCompare$1 = (a, b) => a.localeCompare(b);

    const localeCompareJcouplingKeys$1 = (a, b) => {
      const aa = `${a.diaIDs.sort(localeCompare$1).join(' ')}`;
      const bb = `${b.diaIDs.sort(localeCompare$1).join(' ')}`;
      return localeCompare$1(aa, bb);
    };

    const areThanClose = (a, b, tolerance) => Math.abs(a.coupling - b.coupling) < tolerance;

    const takeCareDiaIDs = (a, b, tolerance) => localeCompareJcouplingKeys$1(a, b) === 0 && areThanClose(a, b, tolerance);
    /**
     * Join couplings smaller than a define tolerance.
     * The resulting coupling should be an average of the existing one.
     * If pathLength is specified and is not always the same this property will be removed.
     */


    function signalJoinCouplings(signal) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        tolerance = 0.05,
        ignoreDiaIDs = false
      } = options;
      if (!signal.js || signal.js.length < 2) return signal;

      if (ignoreDiaIDs) {
        checkJs(signal);
        return groupJCouplings(signal, areThanClose, tolerance);
      } else {
        checkJsAndDiaID(signal);
        return groupJCouplings(signal, takeCareDiaIDs, tolerance);
      }
    }

    function groupJCouplings(signal, comparator, tolerance) {
      signal.js.sort((a, b) => b.coupling - a.coupling);
      let currentGroup = [signal.js[0]];
      let groups = [currentGroup];

      for (let i = 1; i < signal.js.length; i++) {
        let currentJ = signal.js[i];

        if (comparator(currentGroup[currentGroup.length - 1], currentJ, tolerance)) {
          currentGroup.push(currentJ);
        } else {
          currentGroup = [currentJ];
          groups.push(currentGroup);
        }
      }

      signal.js = [];

      for (let group of groups) {
        let coupling = sum(group.map(group => group.coupling)) / group.length;
        let atoms = distinctValues(group.filter(group => group.atoms).map(group => group.atoms).flat());
        let assignment = distinctValues(group.filter(group => group.assignment).map(group => group.assignment).flat()).join(' ');
        let diaIDs = distinctValues(group.filter(group => group.diaIDs).map(group => group.diaIDs).flat());
        let distances = distinctValues(group.map(group => group.pathLength));
        let multiplicity = joinPatterns(group.filter(group => group.multiplicity).map(group => group.multiplicity));
        let newJ = {
          coupling,
          multiplicity
        };
        if (diaIDs.length === 1) newJ.diaIDs = diaIDs;
        if (distances.length === 1 && distances[0]) newJ.pathLength = distances[0];
        if (assignment.length > 0) newJ.assignment = assignment;
        if (atoms.length > 0) newJ.atoms = atoms;
        signal.js.push(newJ);
      }

      return signal;
    }

    function distinctValues(array) {
      const onlyDifferents = new Set();

      for (const element of array) {
        onlyDifferents.add(element);
      }

      return Array.from(onlyDifferents);
    }

    function checkJsAndDiaID(signal) {
      if (!signal.js) throw new Error('there is not js');

      for (const jcoupling of signal.js) {
        if (!jcoupling.diaIDs) throw new Error('there is not diaIDs');
      }
    }

    function checkJs(signal) {
      if (!signal.js) throw new Error('there is not js');
    }

    const localeCompare = (a, b) => a.localeCompare(b);

    const localeCompareJcouplingKeys = (a, b) => {
      const aa = `${a.diaIDs.join(' ')}${a.pathLength}`;
      const bb = `${b.diaIDs.join(' ')}${b.pathLength}`;
      return localeCompare(aa, bb);
    };

    function checkForMandatory$2(signals) {
      for (const signal of signals) {
        if (!signal.js) throw new Error('there is not js');
        if (!signal.diaIDs) throw new Error('there is not diaIDs');

        for (const jcoupling of signal.js) {
          if (!jcoupling.diaIDs) throw new Error('there is not diaIDs');
          if (!jcoupling.pathLength) throw new Error('there is not pathLength');
        }
      }
    }
    /**
     * Join signals if all the same diaID
     */


    function signalsJoin(signals) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      checkForMandatory$2(signals);
      const {
        joinCouplings = {}
      } = options;
      const {
        tolerance,
        ignoreDiaIDs
      } = joinCouplings; // we group them by diaIDs

      const copySignals = JSON.parse(JSON.stringify(signals));
      const groupedSignals = {};

      for (let signal of copySignals) {
        signal.js = signal.js.sort(localeCompareJcouplingKeys);
        const keyDiaIDs = signal.diaIDs.join(' ');
        let id = `${keyDiaIDs} ${signal.js.map(j => `${j.diaIDs.join(' ')} ${j.pathLength}`).sort(localeCompare).join(' ')}`;

        if (!groupedSignals[id]) {
          groupedSignals[id] = [];
        }

        groupedSignals[id].push(signal);
      } // for each group we need to combine assignments and average couplings


      let newSignals = [];
      Object.values(groupedSignals).forEach(group => {
        // joining couplings only if diaID and pathLength are equal
        let js = [];

        for (let i = 0; i < group[0].js.length; i++) {
          const coupling = group[0].js[i];
          js.push({
            diaIDs: coupling.diaIDs,
            pathLength: coupling.pathLength,
            multiplicity: coupling.multiplicity,
            coupling: mean(group.map(item => item.js[i].coupling))
          });
        }

        let signal = {
          id: v4(),
          nbAtoms: sum(group.map(item => item.nbAtoms || 0)),
          delta: mean(group.map(item => item.delta)),
          diaIDs: group[0].diaIDs,
          atoms: group.map(item => item.atoms || []).flat(),
          js
        };
        const assignment = group.map(item => item.assignment).filter(item => item).join(' ');
        if (assignment.length > 0) signal.assignment = assignment;
        newSignals.push(signal);
      });
      newSignals = newSignals.map(signal => {
        let newSignal = signalJoinCouplings(signal, {
          tolerance,
          ignoreDiaIDs
        });

        if (newSignal.js) {
          newSignal.multiplicity = newSignal.js.length > 0 ? newSignal.js.map(j => j.multiplicity).join('') : 's';
        }

        return newSignal;
      }).sort((a, b) => a.delta - b.delta);
      return newSignals;
    }

    function rangeFromSignal(signal, options) {
      const {
        nucleus = '1h',
        frequency = 400
      } = options;
      const {
        tolerance = getTolerance(nucleus) / frequency
      } = options;
      let halfWidth = 0;

      for (const js of signal.js || []) {
        const {
          coupling,
          multiplicity = 'd'
        } = js;
        halfWidth += couplingValues[multiplicity] * coupling / frequency;
      }

      halfWidth = tolerance + halfWidth / 2;
      return {
        from: signal.delta - halfWidth,
        to: signal.delta + halfWidth
      };
    }

    function getTolerance(nucleus) {
      switch (nucleus.toLocaleLowerCase()) {
        case '1h':
          return 1.5;

        case '13C':
          return 3;

        default:
          return 2;
      }
    }

    function checkNbAtoms(signals) {
      for (let signal of signals) {
        if (!signal.nbAtoms) throw new Error('nbAtoms is mandatory');
      }
    }

    function signalsToRanges(signals) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      checkNbAtoms(signals);
      const {
        tolerance = 0.05,
        frequency = 400
      } = options;
      let wrapped = signals.map(signal => ({
        original: signal
      }));
      wrapped.forEach(signal => {
        const fromTo = rangeFromSignal(signal.original, {
          frequency,
          tolerance
        });
        signal.from = fromTo.from;
        signal.to = fromTo.to;
      });
      wrapped = wrapped.sort((signal1, signal2) => signal1.from - signal2.from);
      let ranges = [];
      let range = {};

      for (let signal of wrapped) {
        if (range.from === undefined || signal.from > range.to) {
          range = {
            id: v4(),
            from: signal.from,
            to: signal.to,
            integration: signal.original.nbAtoms,
            signals: [signal.original]
          };
          ranges.push(range);
        } else {
          range.integration += signal.original.nbAtoms;
          if (signal.to > range.to) range.to = signal.to;
          range.signals.push(signal.original);
        }
      }

      return ranges;
    }

    async function predictProton(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        cache
      } = options;
      molecule = molecule.getCompactCopy();
      molecule.addImplicitHydrogens();
      addDiastereotopicMissingChirality(molecule);
      const molfile = molecule.toMolfile();
      let result;

      if (cache) {
        result = cache(molfile);
      }

      if (result === undefined) {
        const formData = new FormData$1();
        formData.append('molfile', molfile);
        const response = await fetch('https://www.nmrdb.org/service/predictor', {
          method: 'POST',
          // @ts-expect-error RequestInit type does not include FormData.
          body: formData
        });
        result = await response.text();

        if (cache) {
          cache(molfile, result);
        }
      }

      const diaIDs = getDiastereotopicAtomIDs(molecule);
      const signals = protonParser(result, molecule, diaIDs);
      const joinedSignals = signalsJoin(signals);
      return {
        molfile,
        diaIDs,
        nucleus: '1H',
        joinedSignals,
        signals,
        ranges: signalsToRanges(joinedSignals),
        molecule
      };
    }

    function protonParser(result, molecule, diaIDs) {
      if (molecule.getAllAtoms() === 0) return [];

      if (result.includes('ERR')) {
        throw Error(`Spinus optimization: ${result}`);
      }

      let distanceMatrix = getConnectivityMatrix(molecule, {
        pathLength: true
      });
      let lines = result.split('\n').filter(line => line);
      let signals = [];

      for (let line of lines) {
        let fields = line.split('\t');
        let couplings = fields.slice(4);
        let atom = Number(fields[0]) - 1;
        let signal = {
          id: v4(),
          atoms: [atom],
          diaIDs: [diaIDs[atom]],
          nbAtoms: 1,
          delta: Number(fields[2]),
          js: []
        };

        if (!signal.js) {
          throw new Error(`For atom js property was not added`);
        }

        for (let i = 0; i < couplings.length; i += 3) {
          let linked = Number(couplings[i]) - 1;
          signal.js.push({
            coupling: Number(couplings[i + 2]),
            atoms: [linked],
            diaIDs: [diaIDs[linked]],
            multiplicity: 'd',
            pathLength: distanceMatrix[atom][linked]
          });
          signal.js.sort((a, b) => b.coupling - a.coupling);
        }

        signals.push(signal);
      }

      return signals;
    }

    const {
      parse: parse$3,
      stringify: stringify$3
    } = JSON;
    function setIDs(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const output = options.output || parse$3(stringify$3(peaks));

      for (const peak of output) {
        peak.id = v4();
      }

      return output;
    }

    async function fetchPrediction(molecule, options) {
      const {
        webserviceURL
      } = options;
      const response = await browserPonyfill.exports.fetch(webserviceURL, {
        headers: {
          accept: 'application/json',
          'content-type': 'application/json'
        },
        body: JSON.stringify({
          molfile: molecule.toMolfile()
        }),
        method: 'POST'
      });
      const prediction = (await response.json()).data;
      prediction.molecule = molecule.getOCL().Molecule.fromMolfile(prediction.molfile);
      return prediction;
    }

    function flatGroupedDiaIDs(groups) {
      let diaIDs = [];

      for (let group of groups) {
        for (let atom of group.atoms) {
          diaIDs[atom] = group.oclID;
        }
      }

      return diaIDs;
    }

    function getFilteredIDiaIDs(molecule, options) {
      const {
        maxSphereSize
      } = options;
      molecule.addImplicitHydrogens();
      molecule.addMissingChirality();
      addDiastereotopicMissingChirality(molecule);
      const molfile = molecule.toMolfile();
      let groupedDiaIDs = getGroupedDiastereotopicAtomIDs(molecule);
      let carbonDiaIDs = groupedDiaIDs.filter(e => e.atomLabel === 'C').sort((a, b) => {
        if (a.atomLabel === b.atomLabel) {
          return b.counter - a.counter;
        }

        return a.atomLabel < b.atomLabel ? 1 : -1;
      });
      const OCL = molecule.getOCL();

      for (const diaId of carbonDiaIDs) {
        diaId.hose = getHoseCodesFromDiastereotopicID(OCL.Molecule.fromIDCode(diaId.oclID), {
          maxSphereSize
        });
      }

      let toReturn = {
        molfile,
        carbonDiaIDs: carbonDiaIDs,
        groupedDiaIDs
      };
      return toReturn;
    }

    function queryByHose(diaIDs, db, options) {
      const {
        maxSphereSize
      } = options;
      const toReturn = [];

      for (const element of diaIDs) {
        let res;
        let level = null;

        for (let k = maxSphereSize; !res && k >= 0; k--) {
          if (db[k]) {
            res = db[k][element.hose[k]];
            level = k;
          }
        }

        for (const atomNumber of element.atoms) {
          let atom = {
            diaIDs: [element.oclID],
            delta: res ? res[0] : null,
            atoms: [atomNumber],
            nbAtoms: 1,
            level,
            statistic: res && res.length > 1 ? {
              mean: res[1],
              sd: res[2],
              min: res[3],
              max: res[4],
              nb: res[5]
            } : undefined
          };
          toReturn.push(atom);
        }
      }

      return toReturn;
    }

    const cache = {};

    async function loadDB() {
      let url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'https://www.lactame.com/lib/nmr-processing-data/20210711/carbon.js';

      if (cache[url]) {
        return cache[url];
      }

      const response = await fetch(url);
      const database = await response.json();
      cache[url] = database;
      return database;
    }

    function checkFromPrediction(signal) {
      if (!signal.atoms) throw new Error('There is not atoms');
      if (!signal.diaIDs) throw new Error('There is not diaIDs');
      if (!signal.nbAtoms) throw new Error('There is not nbAtoms');
    }
    /**
     * Make a query to a hose code based database to predict carbon chemical shift
     * @returns {Promise<object>} - object with molfile, diaIDs, signals, joined signals by diaIDs and ranges.
     */


    async function predictCarbon(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        url,
        database,
        webserviceURL
      } = options;

      if (webserviceURL) {
        return fetchPrediction(molecule, {
          webserviceURL
        });
      }

      if (!database) database = await loadDB(url);

      if (!database) {
        throw new Error('There is not a database');
      }

      const maxLevel = database.length - 1;
      let {
        maxSphereSize = maxLevel
      } = options;
      if (maxSphereSize > maxLevel) maxSphereSize = maxLevel;
      const {
        groupedDiaIDs,
        carbonDiaIDs,
        molfile
      } = getFilteredIDiaIDs(molecule, {
        maxSphereSize
      });
      let predictions = queryByHose(carbonDiaIDs, database, {
        maxSphereSize
      });
      const signals = formatSignals(predictions);
      const joinedSignals = joinSignalByDiaID(signals);
      return {
        molfile,
        nucleus: '13C',
        diaIDs: flatGroupedDiaIDs(groupedDiaIDs),
        joinedSignals,
        signals,
        ranges: signalsToRanges(joinedSignals),
        molecule
      };
    }

    function formatSignals(predictions) {
      let signals = [];

      for (const prediction of predictions) {
        const {
          atoms,
          nbAtoms,
          delta,
          diaIDs,
          statistic
        } = prediction;
        const signal = {
          id: v4(),
          delta: delta || NaN,
          atoms,
          diaIDs,
          multiplicity: 's',
          nbAtoms,
          statistic,
          js: []
        };
        signals.push(signal);
      }

      return signals;
    }

    function joinSignalByDiaID(signals) {
      let joinedSignals = {};

      for (let signal of signals) {
        checkFromPrediction(signal);
        let diaID = signal.diaIDs[0];

        if (!joinedSignals[diaID]) {
          joinedSignals[diaID] = JSON.parse(JSON.stringify(signal));
        } else {
          joinedSignals[diaID].nbAtoms += signal.nbAtoms;
          joinedSignals[diaID].atoms.push(...signal.atoms);
        }
      }

      return setIDs(Object.values(joinedSignals));
    }

    function squaredEuclidean(p, q) {
      let d = 0;

      for (let i = 0; i < p.length; i++) {
        d += (p[i] - q[i]) * (p[i] - q[i]);
      }

      return d;
    }
    function euclidean(p, q) {
      return Math.sqrt(squaredEuclidean(p, q));
    }

    /**
     * Computes a distance/similarity matrix given an array of data and a distance/similarity function.
     * @param {Array} data An array of data
     * @param {function} distanceFn  A function that accepts two arguments and computes a distance/similarity between them
     * @return {Array<Array>} The distance/similarity matrix. The matrix is square and has a size equal to the length of
     * the data array
     */
    function distanceMatrix(data, distanceFn) {
      const result = getMatrix(data.length); // Compute upper distance matrix

      for (let i = 0; i < data.length; i++) {
        for (let j = 0; j <= i; j++) {
          result[i][j] = distanceFn(data[i], data[j]);
          result[j][i] = result[i][j];
        }
      }

      return result;
    }

    function getMatrix(size) {
      const matrix = [];

      for (let i = 0; i < size; i++) {
        const row = [];
        matrix.push(row);

        for (let j = 0; j < size; j++) {
          row.push(0);
        }
      }

      return matrix;
    }

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

    (function (module, exports) {
      // Generated by CoffeeScript 1.8.0
      (function () {
        var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, updateItem, _siftdown, _siftup;

        floor = Math.floor, min = Math.min;
        /*
        Default comparison function to be used
         */

        defaultCmp = function (x, y) {
          if (x < y) {
            return -1;
          }

          if (x > y) {
            return 1;
          }

          return 0;
        };
        /*
        Insert item x in list a, and keep it sorted assuming a is sorted.
        
        If x is already in a, insert it to the right of the rightmost x.
        
        Optional args lo (default 0) and hi (default a.length) bound the slice
        of a to be searched.
         */


        insort = function (a, x, lo, hi, cmp) {
          var mid;

          if (lo == null) {
            lo = 0;
          }

          if (cmp == null) {
            cmp = defaultCmp;
          }

          if (lo < 0) {
            throw new Error('lo must be non-negative');
          }

          if (hi == null) {
            hi = a.length;
          }

          while (lo < hi) {
            mid = floor((lo + hi) / 2);

            if (cmp(x, a[mid]) < 0) {
              hi = mid;
            } else {
              lo = mid + 1;
            }
          }

          return [].splice.apply(a, [lo, lo - lo].concat(x)), x;
        };
        /*
        Push item onto heap, maintaining the heap invariant.
         */


        heappush = function (array, item, cmp) {
          if (cmp == null) {
            cmp = defaultCmp;
          }

          array.push(item);
          return _siftdown(array, 0, array.length - 1, cmp);
        };
        /*
        Pop the smallest item off the heap, maintaining the heap invariant.
         */


        heappop = function (array, cmp) {
          var lastelt, returnitem;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          lastelt = array.pop();

          if (array.length) {
            returnitem = array[0];
            array[0] = lastelt;

            _siftup(array, 0, cmp);
          } else {
            returnitem = lastelt;
          }

          return returnitem;
        };
        /*
        Pop and return the current smallest value, and add the new item.
        
        This is more efficient than heappop() followed by heappush(), and can be
        more appropriate when using a fixed size heap. Note that the value
        returned may be larger than item! That constrains reasonable use of
        this routine unless written as part of a conditional replacement:
            if item > array[0]
              item = heapreplace(array, item)
         */


        heapreplace = function (array, item, cmp) {
          var returnitem;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          returnitem = array[0];
          array[0] = item;

          _siftup(array, 0, cmp);

          return returnitem;
        };
        /*
        Fast version of a heappush followed by a heappop.
         */


        heappushpop = function (array, item, cmp) {
          var _ref;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          if (array.length && cmp(array[0], item) < 0) {
            _ref = [array[0], item], item = _ref[0], array[0] = _ref[1];

            _siftup(array, 0, cmp);
          }

          return item;
        };
        /*
        Transform list into a heap, in-place, in O(array.length) time.
         */


        heapify = function (array, cmp) {
          var i, _i, _len, _ref1, _results, _results1;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          _ref1 = function () {
            _results1 = [];

            for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--) {
              _results1.push(_j);
            }

            return _results1;
          }.apply(this).reverse();

          _results = [];

          for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
            i = _ref1[_i];

            _results.push(_siftup(array, i, cmp));
          }

          return _results;
        };
        /*
        Update the position of the given item in the heap.
        This function should be called every time the item is being modified.
         */


        updateItem = function (array, item, cmp) {
          var pos;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          pos = array.indexOf(item);

          if (pos === -1) {
            return;
          }

          _siftdown(array, 0, pos, cmp);

          return _siftup(array, pos, cmp);
        };
        /*
        Find the n largest elements in a dataset.
         */


        nlargest = function (array, n, cmp) {
          var elem, result, _i, _len, _ref;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          result = array.slice(0, n);

          if (!result.length) {
            return result;
          }

          heapify(result, cmp);
          _ref = array.slice(n);

          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            elem = _ref[_i];
            heappushpop(result, elem, cmp);
          }

          return result.sort(cmp).reverse();
        };
        /*
        Find the n smallest elements in a dataset.
         */


        nsmallest = function (array, n, cmp) {
          var elem, los, result, _i, _j, _len, _ref, _ref1, _results;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          if (n * 10 <= array.length) {
            result = array.slice(0, n).sort(cmp);

            if (!result.length) {
              return result;
            }

            los = result[result.length - 1];
            _ref = array.slice(n);

            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              elem = _ref[_i];

              if (cmp(elem, los) < 0) {
                insort(result, elem, 0, null, cmp);
                result.pop();
                los = result[result.length - 1];
              }
            }

            return result;
          }

          heapify(array, cmp);
          _results = [];

          for (_j = 0, _ref1 = min(n, array.length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; 0 <= _ref1 ? ++_j : --_j) {
            _results.push(heappop(array, cmp));
          }

          return _results;
        };

        _siftdown = function (array, startpos, pos, cmp) {
          var newitem, parent, parentpos;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          newitem = array[pos];

          while (pos > startpos) {
            parentpos = pos - 1 >> 1;
            parent = array[parentpos];

            if (cmp(newitem, parent) < 0) {
              array[pos] = parent;
              pos = parentpos;
              continue;
            }

            break;
          }

          return array[pos] = newitem;
        };

        _siftup = function (array, pos, cmp) {
          var childpos, endpos, newitem, rightpos, startpos;

          if (cmp == null) {
            cmp = defaultCmp;
          }

          endpos = array.length;
          startpos = pos;
          newitem = array[pos];
          childpos = 2 * pos + 1;

          while (childpos < endpos) {
            rightpos = childpos + 1;

            if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) {
              childpos = rightpos;
            }

            array[pos] = array[childpos];
            pos = childpos;
            childpos = 2 * pos + 1;
          }

          array[pos] = newitem;
          return _siftdown(array, startpos, pos, cmp);
        };

        Heap = function () {
          Heap.push = heappush;
          Heap.pop = heappop;
          Heap.replace = heapreplace;
          Heap.pushpop = heappushpop;
          Heap.heapify = heapify;
          Heap.updateItem = updateItem;
          Heap.nlargest = nlargest;
          Heap.nsmallest = nsmallest;

          function Heap(cmp) {
            this.cmp = cmp != null ? cmp : defaultCmp;
            this.nodes = [];
          }

          Heap.prototype.push = function (x) {
            return heappush(this.nodes, x, this.cmp);
          };

          Heap.prototype.pop = function () {
            return heappop(this.nodes, this.cmp);
          };

          Heap.prototype.peek = function () {
            return this.nodes[0];
          };

          Heap.prototype.contains = function (x) {
            return this.nodes.indexOf(x) !== -1;
          };

          Heap.prototype.replace = function (x) {
            return heapreplace(this.nodes, x, this.cmp);
          };

          Heap.prototype.pushpop = function (x) {
            return heappushpop(this.nodes, x, this.cmp);
          };

          Heap.prototype.heapify = function () {
            return heapify(this.nodes, this.cmp);
          };

          Heap.prototype.updateItem = function (x) {
            return updateItem(this.nodes, x, this.cmp);
          };

          Heap.prototype.clear = function () {
            return this.nodes = [];
          };

          Heap.prototype.empty = function () {
            return this.nodes.length === 0;
          };

          Heap.prototype.size = function () {
            return this.nodes.length;
          };

          Heap.prototype.clone = function () {
            var heap;
            heap = new Heap();
            heap.nodes = this.nodes.slice(0);
            return heap;
          };

          Heap.prototype.toArray = function () {
            return this.nodes.slice(0);
          };

          Heap.prototype.insert = Heap.prototype.push;
          Heap.prototype.top = Heap.prototype.peek;
          Heap.prototype.front = Heap.prototype.peek;
          Heap.prototype.has = Heap.prototype.contains;
          Heap.prototype.copy = Heap.prototype.clone;
          return Heap;
        }();

        (function (root, factory) {
          {
            return module.exports = factory();
          }
        })(this, function () {
          return Heap;
        });
      }).call(commonjsGlobal);
    })(heap$1);

    var heap = heap$1.exports;
    var Heap = heap;

    class Cluster {
      constructor() {
        this.children = [];
        this.height = 0;
        this.size = 1;
        this.index = -1;
        this.isLeaf = false;
      }
      /**
       * Creates an array of clusters where the maximum height is smaller than the threshold
       * @param {number} threshold
       * @return {Array<Cluster>}
       */


      cut(threshold) {
        if (typeof threshold !== 'number') {
          throw new TypeError('threshold must be a number');
        }

        if (threshold < 0) {
          throw new RangeError('threshold must be a positive number');
        }

        let list = [this];
        const ans = [];

        while (list.length > 0) {
          const aux = list.shift();

          if (threshold >= aux.height) {
            ans.push(aux);
          } else {
            list = list.concat(aux.children);
          }
        }

        return ans;
      }
      /**
       * Merge the leaves in the minimum way to have `groups` number of clusters.
       * @param {number} groups - Them number of children the first level of the tree should have.
       * @return {Cluster}
       */


      group(groups) {
        if (!Number.isInteger(groups) || groups < 1) {
          throw new RangeError('groups must be a positive integer');
        }

        const heap = new Heap((a, b) => {
          return b.height - a.height;
        });
        heap.push(this);

        while (heap.size() < groups) {
          const first = heap.pop();

          if (first.children.length === 0) {
            break;
          }

          first.children.forEach(child => heap.push(child));
        }

        const root = new Cluster();
        root.children = heap.toArray();
        root.height = this.height;
        return root;
      }
      /**
       * Traverses the tree depth-first and calls the provided callback with each individual node
       * @param {function} cb - The callback to be called on each node encounter
       */


      traverse(cb) {
        function visit(root, callback) {
          callback(root);

          if (root.children) {
            for (const child of root.children) {
              visit(child, callback);
            }
          }
        }

        visit(this, cb);
      }
      /**
       * Returns a list of indices for all the leaves of this cluster.
       * The list is ordered in such a way that a dendrogram could be drawn without crossing branches.
       * @returns {Array<number>}
       */


      indices() {
        const result = [];
        this.traverse(cluster => {
          if (cluster.isLeaf) {
            result.push(cluster.index);
          }
        });
        return result;
      }

    }

    function singleLink(dKI, dKJ) {
      return Math.min(dKI, dKJ);
    }

    function completeLink(dKI, dKJ) {
      return Math.max(dKI, dKJ);
    }

    function averageLink(dKI, dKJ, dIJ, ni, nj) {
      const ai = ni / (ni + nj);
      const aj = nj / (ni + nj);
      return ai * dKI + aj * dKJ;
    }

    function weightedAverageLink(dKI, dKJ) {
      return (dKI + dKJ) / 2;
    }

    function centroidLink(dKI, dKJ, dIJ, ni, nj) {
      const ai = ni / (ni + nj);
      const aj = nj / (ni + nj);
      const b = -(ni * nj) / (ni + nj) ** 2;
      return ai * dKI + aj * dKJ + b * dIJ;
    }

    function medianLink(dKI, dKJ, dIJ) {
      return dKI / 2 + dKJ / 2 - dIJ / 4;
    }

    function wardLink(dKI, dKJ, dIJ, ni, nj, nk) {
      const ai = (ni + nk) / (ni + nj + nk);
      const aj = (nj + nk) / (ni + nj + nk);
      const b = -nk / (ni + nj + nk);
      return ai * dKI + aj * dKJ + b * dIJ;
    }

    function wardLink2(dKI, dKJ, dIJ, ni, nj, nk) {
      const ai = (ni + nk) / (ni + nj + nk);
      const aj = (nj + nk) / (ni + nj + nk);
      const b = -nk / (ni + nj + nk);
      return Math.sqrt(ai * dKI * dKI + aj * dKJ * dKJ + b * dIJ * dIJ);
    }
    /**
     * Continuously merge nodes that have the least dissimilarity
     * @param {Array<Array<number>>} data - Array of points to be clustered
     * @param {object} [options]
     * @param {Function} [options.distanceFunction]
     * @param {string} [options.method] - Default: `'complete'`
     * @param {boolean} [options.isDistanceMatrix] - Is the input already a distance matrix?
     * @constructor
     */


    function agnes(data) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        distanceFunction = euclidean,
        method = 'complete',
        isDistanceMatrix = false
      } = options;
      let updateFunc;

      if (!isDistanceMatrix) {
        data = distanceMatrix(data, distanceFunction);
      }

      let distanceMatrix$1 = new Matrix(data);
      const numLeaves = distanceMatrix$1.rows; // allows to use a string or a given function

      if (typeof method === 'string') {
        switch (method.toLowerCase()) {
          case 'single':
            updateFunc = singleLink;
            break;

          case 'complete':
            updateFunc = completeLink;
            break;

          case 'average':
          case 'upgma':
            updateFunc = averageLink;
            break;

          case 'wpgma':
            updateFunc = weightedAverageLink;
            break;

          case 'centroid':
          case 'upgmc':
            updateFunc = centroidLink;
            break;

          case 'median':
          case 'wpgmc':
            updateFunc = medianLink;
            break;

          case 'ward':
            updateFunc = wardLink;
            break;

          case 'ward2':
            updateFunc = wardLink2;
            break;

          default:
            throw new RangeError(`unknown clustering method: ${method}`);
        }
      } else if (typeof method !== 'function') {
        throw new TypeError('method must be a string or function');
      }

      let clusters = [];

      for (let i = 0; i < numLeaves; i++) {
        const cluster = new Cluster();
        cluster.isLeaf = true;
        cluster.index = i;
        clusters.push(cluster);
      }

      for (let n = 0; n < numLeaves - 1; n++) {
        const [row, column, distance] = getSmallestDistance(distanceMatrix$1);
        const cluster1 = clusters[row];
        const cluster2 = clusters[column];
        const newCluster = new Cluster();
        newCluster.size = cluster1.size + cluster2.size;
        newCluster.children.push(cluster1, cluster2);
        newCluster.height = distance;
        const newClusters = [newCluster];
        const newDistanceMatrix = new Matrix(distanceMatrix$1.rows - 1, distanceMatrix$1.rows - 1);

        const previous = newIndex => getPreviousIndex(newIndex, Math.min(row, column), Math.max(row, column));

        for (let i = 1; i < newDistanceMatrix.rows; i++) {
          const prevI = previous(i);
          const prevICluster = clusters[prevI];
          newClusters.push(prevICluster);

          for (let j = 0; j < i; j++) {
            if (j === 0) {
              const dKI = distanceMatrix$1.get(row, prevI);
              const dKJ = distanceMatrix$1.get(prevI, column);
              const val = updateFunc(dKI, dKJ, distance, cluster1.size, cluster2.size, prevICluster.size);
              newDistanceMatrix.set(i, j, val);
              newDistanceMatrix.set(j, i, val);
            } else {
              // Just copy distance from previous matrix
              const val = distanceMatrix$1.get(prevI, previous(j));
              newDistanceMatrix.set(i, j, val);
              newDistanceMatrix.set(j, i, val);
            }
          }
        }

        clusters = newClusters;
        distanceMatrix$1 = newDistanceMatrix;
      }

      return clusters[0];
    }

    function getSmallestDistance(distance) {
      let smallest = Infinity;
      let smallestI = 0;
      let smallestJ = 0;

      for (let i = 1; i < distance.rows; i++) {
        for (let j = 0; j < i; j++) {
          if (distance.get(i, j) < smallest) {
            smallest = distance.get(i, j);
            smallestI = i;
            smallestJ = j;
          }
        }
      }

      return [smallestI, smallestJ, smallest];
    }

    function getPreviousIndex(newIndex, prev1, prev2) {
      newIndex -= 1;
      if (newIndex >= prev1) newIndex++;
      if (newIndex >= prev2) newIndex++;
      return newIndex;
    }

    const nucleusMap = {
      h: '1H',
      c: '13C'
    };
    function getNuclei(input) {
      return Object.values(input).map(e => nucleusMap[e.toLowerCase()]);
    }

    async function getPredictions(key, molecule, predictOptions, predictor, predictions) {
      let prediction;

      if (predictions === null || predictions === void 0 ? void 0 : predictions[key]) {
        prediction = predictions[key];
      } else if (predictor) {
        const fromPredictor = predictor[key];
        prediction = fromPredictor ? await fromPredictor(molecule, predictOptions[key]) : undefined;
      }

      return prediction;
    }

    function checkFromTo(options) {
      if (!options.from || !options.to) {
        throw new Error('options from and to are mandatory');
      }
    }

    async function predict2D(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      checkFromTo(options);
      let {
        from,
        to,
        minLength = 0,
        maxLength,
        predictOptions = {},
        predictions,
        predictor,
        joinDistance = {
          H: 0.05,
          C: 0.5
        },
        includeDiagonal = false
      } = options;
      molecule.addImplicitHydrogens();
      let diaIDs = getGroupedDiastereotopicAtomIDs(molecule);
      const pathsInfo = getPathsInfo(molecule, {
        fromLabel: from,
        toLabel: to,
        minLength,
        maxLength
      });
      let diaIDswithAtomInfo = [];

      for (let diaID of diaIDs) {
        diaIDswithAtomInfo.push({ ...diaID,
          pathInfo: JSON.parse(JSON.stringify(pathsInfo[diaID.atoms[0]]))
        });
      }

      const xPrediction = await getPredictions(from, molecule, predictOptions, predictor, predictions);
      const yPrediction = from === to ? xPrediction : await getPredictions(to, molecule, predictOptions, predictor, predictions);

      if (!xPrediction || !yPrediction) {
        throw new Error('predictions are not availaible');
      }

      const spectra = {
        x: xPrediction,
        y: yPrediction
      };
      const signalsByDiaID = {
        x: {},
        y: {}
      };

      for (const axis in signalsByDiaID) {
        for (const signal of spectra[axis].joinedSignals) {
          if (!signal.diaIDs) throw new Error('Signal has not diaIDs');
          signalsByDiaID[axis][signal.diaIDs[0]] = signal;
        }
      }

      let group = {};

      for (const diaID of diaIDswithAtomInfo) {
        const pathInfo = diaID.pathInfo;
        if (pathInfo.paths.length < 1) continue;
        if (!signalsByDiaID.x[pathInfo.oclID]) continue;
        const currentPaths = pathInfo.paths;

        for (const path of currentPaths) {
          if (!signalsByDiaID.y[pathsInfo[path.to].oclID]) continue;
          let fromToDiaID = {
            x: pathInfo,
            y: pathsInfo[path.to]
          };
          const key = `${fromToDiaID.x.oclID}-${fromToDiaID.y.oclID}`;

          if (key === `${pathInfo.oclID}-${pathInfo.oclID}` || group[key]) {
            continue;
          }

          let peak = {
            id: v4(),
            z: 100
          };
          let signal = {
            id: v4(),
            x: {},
            y: {}
          };

          for (let axis in fromToDiaID) {
            let diaID = fromToDiaID[axis].oclID;
            peak[axis] = signalsByDiaID[axis][diaID].delta;
            signal[axis].delta = signalsByDiaID[axis][diaID].delta;
            signal[axis].diaIDs = [diaID];
            signal[axis].atoms = signalsByDiaID[axis][diaID].atoms;
          }

          signal.peaks = [peak];
          group[key] = signal;
        }
      }

      if (includeDiagonal) {
        addSelftCorrelation(group, {
          paths: pathsInfo,
          signalsByDiaID
        });
      } // clusterize signals by distance


      const joinedSignals = Object.values(group);
      const zones = createZones(joinedSignals, {
        joinDistance,
        from,
        to
      });
      return {
        molfile: molecule.toMolfile(),
        diaIDs: spectra.x.diaIDs,
        nuclei: getNuclei({
          from,
          to
        }),
        joinedSignals,
        signals: splitSignals(joinedSignals),
        zones,
        molecule
      };
    }

    function splitSignals(joinedSignals) {
      let signals = [];

      for (const signal of joinedSignals) {
        for (const xAtom of signal.x.atoms || []) {
          for (const yAtom of signal.y.atoms || []) {
            let newSignal = JSON.parse(JSON.stringify(signal));
            newSignal.x.atoms = [xAtom];
            newSignal.y.atoms = [yAtom];
            signals.push(newSignal);
          }
        }
      }

      return setIDs(signals);
    }

    function addSelftCorrelation(group, options) {
      const {
        paths = [],
        signalsByDiaID
      } = options;

      for (const atom of paths) {
        if (atom.paths.length < 1) continue;
        let diaID = atom.oclID;
        if (!signalsByDiaID.x[diaID]) continue;
        if (group[`${diaID}-${diaID}`]) continue;
        let signal = {
          x: {},
          y: {}
        };
        let peak = {
          z: 1
        };

        for (let axis of ['x', 'y']) {
          peak[axis] = signalsByDiaID[axis][diaID].delta;
          signal[axis].delta = signalsByDiaID[axis][diaID].delta;
          signal[axis].diaIDs = [diaID];
          signal[axis].atoms = signalsByDiaID[axis][diaID].atoms;
        }

        signal.peaks = [peak];
        group[`${atom.oclID}-${atom.oclID}`] = signal;
      }
    }

    function createZones(signals, options) {
      const {
        joinDistance,
        from,
        to
      } = options;
      const deltas = new Matrix(signals.map(e => [e.x.delta, e.y.delta]));
      const minX = deltas.minColumn(0);
      const maxX = deltas.maxColumn(0);
      const minY = deltas.minColumn(1);
      const maxY = deltas.maxColumn(1);
      deltas.mulColumn(0, 1 / (maxX - minX));
      deltas.mulColumn(1, 1 / (maxY - minY));
      const cutOff = Math.sqrt(Math.pow(joinDistance[from] / (maxX - minX), 2) + Math.pow(joinDistance[to] / (maxY - minY), 2));
      let hClusters = agnes(deltas.to2DArray(), {
        method: 'centroid'
      });
      const clusters = splitClusters([hClusters], cutOff);
      const zones = [];

      for (const cluster of clusters) {
        const signal = [];
        if (cluster.isLeaf) signal.push(signals[cluster.index]);

        for (const child of cluster.children) {
          for (const index of child.indices()) {
            signal.push(signals[index]);
          }
        }

        zones.push({
          id: v4(),
          ...fromTo(signal, {
            joinDistance,
            from,
            to
          }),
          signals: signal
        });
      }

      return zones;
    }

    function fromTo(signals, options) {
      const {
        joinDistance,
        from,
        to
      } = options;
      let minX = Number.MAX_SAFE_INTEGER;
      let minY = Number.MAX_SAFE_INTEGER;
      let maxX = Number.MIN_SAFE_INTEGER;
      let maxY = Number.MIN_SAFE_INTEGER;

      for (const signal of signals) {
        if (signal.x.delta < minX) minX = signal.x.delta;
        if (signal.x.delta > maxX) maxX = signal.x.delta;
        if (signal.y.delta < minY) minY = signal.y.delta;
        if (signal.y.delta > maxY) maxY = signal.y.delta;
      }

      return {
        x: {
          from: minX - joinDistance[from],
          to: maxX + joinDistance[from]
        },
        y: {
          from: minY - joinDistance[to],
          to: maxY + joinDistance[to]
        }
      };
    }

    function splitClusters(clusters, maxDistance) {
      let originalLength = clusters.length;

      for (let i = 0; i < clusters.length; i++) {
        const cluster = clusters[i];

        if (cluster.height > maxDistance) {
          clusters.push(...cluster.children);
          clusters.splice(i--, 1);
        }
      }

      return clusters.length < originalLength ? splitClusters(clusters, maxDistance) : clusters;
    }

    /**
     * Generate the correlation bidimensional nmr peaks based on the number of bonds between a pair of atoms
     * @returns {Promise<object>} - object with molfile, diaIDs, 2D signals joined signals and zones.
     */

    async function predictCOSY(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        minLength = 2,
        maxLength = 3,
        predictions,
        predictor = {
          H: predictProton
        },
        predictOptions,
        joinDistance = {
          H: 0.05,
          C: 0.5
        },
        includeDiagonal = true
      } = options;
      return predict2D(molecule, {
        from: 'H',
        to: 'H',
        predictor,
        minLength,
        maxLength,
        joinDistance,
        predictions,
        includeDiagonal,
        predictOptions
      });
    }

    /**
     * Generate the correlation bidimensional nmr peaks based on the number of bonds between a pair of atoms
     * @returns {Promise<object>} - object with molfile, diaIDs, 2D signals joined signals and zones.
     */

    async function predictHSQC(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        minLength = 1,
        maxLength = 1,
        predictor = {
          H: predictProton,
          C: predictCarbon
        },
        predictions,
        joinDistance = {
          H: 0.05,
          C: 0.5
        },
        predictOptions
      } = options;
      return predict2D(molecule, {
        from: 'H',
        to: 'C',
        predictor,
        minLength,
        maxLength,
        predictions,
        predictOptions,
        joinDistance
      });
    }

    async function predictHMBC(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        minLength = 2,
        maxLength = 3,
        predictor = {
          H: predictProton,
          C: predictCarbon
        },
        predictOptions,
        predictions,
        joinDistance = {
          H: 0.05,
          C: 0.5
        }
      } = options;
      return predict2D(molecule, {
        from: 'H',
        to: 'C',
        predictor,
        minLength,
        maxLength,
        predictions,
        predictOptions,
        joinDistance
      });
    }

    /**
     * Generate the correlation bidimensional nmr peaks based on the number of bonds between a pair of atoms
     * @returns {Promise<object>} - object with molfile, diaIDs, 1D and 2D signals, joined signals, ranges and zones.
     */

    async function predictAll(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        from = 'H',
        to = 'C',
        predictor = {
          H: predictProton,
          C: predictCarbon
        },
        predictions,
        joinDistance = {
          H: 0.05,
          C: 0.5
        },
        predictOptions = {}
      } = options;
      const xPrediction = await getPredictions(from, molecule, predictOptions, predictor, predictions);
      const yPrediction = await getPredictions(to, molecule, predictOptions, predictor, predictions);

      if (!xPrediction || !yPrediction) {
        throw new Error('predictions are not availaible');
      }

      predictions = {
        H: xPrediction,
        C: yPrediction
      };
      const {
        molfile,
        diaIDs
      } = xPrediction;
      const spectra = {
        proton: predictions.H,
        carbon: predictions.C
      };
      spectra.cosy = await predictCOSY(molecule, {
        predictions,
        joinDistance
      });
      spectra.hsqc = await predictHSQC(molecule, {
        predictions,
        joinDistance
      });
      spectra.hmbc = await predictHMBC(molecule, {
        predictions,
        joinDistance
      });

      for (const key in spectra) {
        delete spectra[key].molfile;
        delete spectra[key].diaIDs;
      }

      return {
        molfile,
        diaIDs,
        ...spectra
      };
    }

    function signals2DToZ(signals) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        from = -1,
        to = 12,
        nbPoints = 512,
        width = 0.02,
        factor = 3
      } = options;
      const peaks = signals.reduce((acc, _ref) => {
        let {
          x,
          y
        } = _ref;
        acc.x.push(x.delta);
        acc.y.push(y.delta);
        acc.z.push(1e6);
        return acc;
      }, {
        x: [],
        y: [],
        z: []
      });
      width = ensureXYNumber(width);
      return generateSpectrum2D(mergeClosePeaks(peaks), {
        generator: {
          from: ensureXYNumber(from),
          to: ensureXYNumber(to),
          nbPoints: ensureXYNumber(nbPoints)
        },
        peaks: {
          width,
          factor
        }
      });
    }

    function ensureXYNumber(input) {
      return typeof input !== 'object' ? {
        x: input,
        y: input
      } : { ...input
      };
    }

    function mergeClosePeaks(peaksIn) {
      let peaks = JSON.parse(JSON.stringify(peaksIn));

      for (let i = 0; i < peaks.x.length; i++) {
        for (let j = i + 1; j < peaks.x.length; j++) {
          if (peaks.x[i] === peaks.x[j] && peaks.y[i] === peaks.y[j]) {
            peaks.z[i] += peaks.z[j];
            peaks.x.splice(j, 1);
            peaks.y.splice(j, 1);
            peaks.z.splice(j, 1);
            j--;
          }
        }
      }

      return peaks;
    }

    /**
     * Created by acastillo on 8/8/16.
     */

    const defOptions = {
      threshold: 0,
      out: "assignment"
    }; //TODO Consider a matrix of distances too

    var src$2 = function fullClusterGenerator(conMat, opt) {
      const options = Object.assign({}, defOptions, opt);
      var clList, i, j, k;

      if (typeof conMat[0] === "number") {
        clList = fullClusterGeneratorVector(conMat);
      } else {
        if (typeof conMat[0] === "object") {
          var nRows = conMat.length;
          var conn = new Array(nRows * (nRows + 1) / 2);
          var index = 0;

          for (var i = 0; i < nRows; i++) {
            for (var j = i; j < nRows; j++) {
              if (conMat[i][j] > options.threshold) conn[index++] = 1;else conn[index++] = 0;
            }
          }

          clList = fullClusterGeneratorVector(conn);
        }
      }

      if (options.out === "indexes" || options.out === "values") {
        var result = new Array(clList.length);

        for (i = 0; i < clList.length; i++) {
          result[i] = [];

          for (j = 0; j < clList[i].length; j++) {
            if (clList[i][j] != 0) {
              result[i].push(j);
            }
          }
        }

        if (options.out === "values") {
          var resultAsMatrix = new Array(result.length);

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

            for (j = 0; j < result[i].length; j++) {
              resultAsMatrix[i][j] = new Array(result[i].length);

              for (k = 0; k < result[i].length; k++) {
                resultAsMatrix[i][j][k] = conMat[result[i][j]][result[i][k]];
              }
            }
          }

          return resultAsMatrix;
        } else {
          return result;
        }
      }

      return clList;
    };

    function fullClusterGeneratorVector(conn) {
      var nRows = Math.sqrt(conn.length * 2 + 0.25) - 0.5;
      var clusterList = [];
      var available = new Array(nRows);
      var remaining = nRows,
          i = 0;
      var cluster = []; //Mark all the elements as available

      for (i = nRows - 1; i >= 0; i--) {
        available[i] = 1;
      }

      var nextAv = -1;
      var toInclude = [];

      while (remaining > 0) {
        if (toInclude.length === 0) {
          //If there is no more elements to include. Start a new cluster
          cluster = new Array(nRows);

          for (i = 0; i < nRows; i++) cluster[i] = 0;

          clusterList.push(cluster);

          for (nextAv = 0; available[nextAv] == 0; nextAv++) {}
        } else {
          nextAv = toInclude.splice(0, 1);
        }

        cluster[nextAv] = 1;
        available[nextAv] = 0;
        remaining--; //Copy the next available row

        var row = new Array(nRows);

        for (i = 0; i < nRows; i++) {
          var c = Math.max(nextAv, i);
          var r = Math.min(nextAv, i); //The element in the conn matrix
          //console.log("index: "+r*(2*nRows-r-1)/2+c)

          row[i] = conn[r * (2 * nRows - r - 1) / 2 + c]; //There is new elements to include in this row?
          //Then, include it to the current cluster

          if (row[i] == 1 && available[i] == 1 && cluster[i] == 0) {
            toInclude.push(i);
            cluster[i] = 1;
          }
        }
      }

      return clusterList;
    }

    var simpleClustering = src$2;

    function checkForMandatory$1(signals) {
      for (const signal of signals) {
        if (!signal.js) throw new Error('there is not js');
        if (!signal.atoms) throw new Error('there is not atoms');

        for (const jcoupling of signal.js) {
          if (!jcoupling.atoms) throw new Error('there is not atoms');
        }
      }
    }

    function signalsToSpinSystem(signals) {
      checkForMandatory$1(signals);
      const nSpins = signals.length;
      const chemicalShifts = new Array(nSpins);
      const multiplicity = new Array(nSpins);
      const couplingConstants = Matrix.zeros(nSpins, nSpins); //create a list of assignments

      const ids = {};

      for (let i = 0; i < nSpins; i++) {
        multiplicity[i] = 2;
        chemicalShifts[i] = signals[i].delta;
        const index = signals[i].atoms[0];
        ids[index] = i;
      } //create the coupling matrix


      for (let i = 0; i < nSpins; i++) {
        let {
          atoms: signalAssignment,
          js: jCoupling
        } = signals[i];
        const fromIndex = signalAssignment[0];

        for (const jcoupling of jCoupling) {
          let {
            coupling,
            atoms
          } = jcoupling;
          const toIndex = atoms[0];
          couplingConstants.set(ids[fromIndex], ids[toIndex], coupling);
          couplingConstants.set(ids[toIndex], ids[fromIndex], coupling);
        }
      }

      const connectivity = Matrix.ones(couplingConstants.rows, couplingConstants.rows);

      for (let i = 0; i < couplingConstants.rows; i++) {
        for (let j = i; j < couplingConstants.columns; j++) {
          if (couplingConstants.get(i, j) === 0) {
            connectivity.set(i, j, 0);
            connectivity.set(j, i, 0);
          }
        }
      }

      let clusters = simpleClustering(connectivity.to2DArray(), {
        out: 'indexes'
      });
      return {
        clusters,
        couplingConstants,
        chemicalShifts,
        multiplicity,
        connectivity
      };
    }

    var binarySearch = function (haystack, needle, comparator, low, high) {
      var mid, cmp;
      if (low === undefined) low = 0;else {
        low = low | 0;
        if (low < 0 || low >= haystack.length) throw new RangeError("invalid lower bound");
      }
      if (high === undefined) high = haystack.length - 1;else {
        high = high | 0;
        if (high < low || high >= haystack.length) throw new RangeError("invalid upper bound");
      }

      while (low <= high) {
        // The naive `low + high >>> 1` could fail for array lengths > 2**31
        // because `>>>` converts its operands to int32. `low + (high - low >>> 1)`
        // works for array lengths <= 2**32-1 which is also Javascript's max array
        // length.
        mid = low + (high - low >>> 1);
        cmp = +comparator(haystack[mid], needle, mid, haystack); // Too low.

        if (cmp < 0.0) low = mid + 1; // Too high.
        else if (cmp > 0.0) high = mid - 1; // Key found.
        else return mid;
      } // Key not found.


      return ~low;
    };

    var binarySearch$1 = binarySearch;

    var numSort = {};

    function assertNumber(number) {
      if (typeof number !== 'number') {
        throw new TypeError('Expected a number');
      }
    }

    var ascending = numSort.ascending = (left, right) => {
      assertNumber(left);
      assertNumber(right);

      if (Number.isNaN(left)) {
        return -1;
      }

      if (Number.isNaN(right)) {
        return 1;
      }

      return left - right;
    };

    numSort.descending = (left, right) => {
      assertNumber(left);
      assertNumber(right);

      if (Number.isNaN(left)) {
        return 1;
      }

      if (Number.isNaN(right)) {
        return -1;
      }

      return right - left;
    };

    const largestPrime = 0x7fffffff;
    const primeNumbers = [// chunk #0
    largestPrime, // 2^31-1
    // chunk #1
    5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, 25717, 51437, 102877, 205759, 411527, 823117, 1646237, 3292489, 6584983, 13169977, 26339969, 52679969, 105359939, 210719881, 421439783, 842879579, 1685759167, // chunk #2
    433, 877, 1759, 3527, 7057, 14143, 28289, 56591, 113189, 226379, 452759, 905551, 1811107, 3622219, 7244441, 14488931, 28977863, 57955739, 115911563, 231823147, 463646329, 927292699, 1854585413, // chunk #3
    953, 1907, 3821, 7643, 15287, 30577, 61169, 122347, 244703, 489407, 978821, 1957651, 3915341, 7830701, 15661423, 31322867, 62645741, 125291483, 250582987, 501165979, 1002331963, 2004663929, // chunk #4
    1039, 2081, 4177, 8363, 16729, 33461, 66923, 133853, 267713, 535481, 1070981, 2141977, 4283963, 8567929, 17135863, 34271747, 68543509, 137087021, 274174111, 548348231, 1096696463, // chunk #5
    31, 67, 137, 277, 557, 1117, 2237, 4481, 8963, 17929, 35863, 71741, 143483, 286973, 573953, 1147921, 2295859, 4591721, 9183457, 18366923, 36733847, 73467739, 146935499, 293871013, 587742049, 1175484103, // chunk #6
    599, 1201, 2411, 4831, 9677, 19373, 38747, 77509, 155027, 310081, 620171, 1240361, 2480729, 4961459, 9922933, 19845871, 39691759, 79383533, 158767069, 317534141, 635068283, 1270136683, // chunk #7
    311, 631, 1277, 2557, 5119, 10243, 20507, 41017, 82037, 164089, 328213, 656429, 1312867, 2625761, 5251529, 10503061, 21006137, 42012281, 84024581, 168049163, 336098327, 672196673, 1344393353, // chunk #8
    3, 7, 17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719, 175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671, 44917381, 89834777, 179669557, 359339171, 718678369, 1437356741, // chunk #9
    43, 89, 179, 359, 719, 1439, 2879, 5779, 11579, 23159, 46327, 92657, 185323, 370661, 741337, 1482707, 2965421, 5930887, 11861791, 23723597, 47447201, 94894427, 189788857, 379577741, 759155483, 1518310967, // chunk #10
    379, 761, 1523, 3049, 6101, 12203, 24407, 48817, 97649, 195311, 390647, 781301, 1562611, 3125257, 6250537, 12501169, 25002389, 50004791, 100009607, 200019221, 400038451, 800076929, 1600153859, // chunk #11
    13, 29, 59, 127, 257, 521, 1049, 2099, 4201, 8419, 16843, 33703, 67409, 134837, 269683, 539389, 1078787, 2157587, 4315183, 8630387, 17260781, 34521589, 69043189, 138086407, 276172823, 552345671, 1104691373, // chunk #12
    19, 41, 83, 167, 337, 677, 1361, 2729, 5471, 10949, 21911, 43853, 87719, 175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671, 44917381, 89834777, 179669557, 359339171, 718678369, 1437356741, // chunk #13
    53, 107, 223, 449, 907, 1823, 3659, 7321, 14653, 29311, 58631, 117269, 234539, 469099, 938207, 1876417, 3752839, 7505681, 15011389, 30022781, 60045577, 120091177, 240182359, 480364727, 960729461, 1921458943];
    primeNumbers.sort(ascending);
    function nextPrime(value) {
      let index = binarySearch$1(primeNumbers, value, ascending);

      if (index < 0) {
        index = ~index;
      }

      return primeNumbers[index];
    }

    const FREE = 0;
    const FULL = 1;
    const REMOVED = 2;
    const defaultInitialCapacity = 150;
    const defaultMinLoadFactor = 1 / 6;
    const defaultMaxLoadFactor = 2 / 3;
    class HashTable {
      constructor() {
        let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        if (options instanceof HashTable) {
          this.table = options.table.slice();
          this.values = options.values.slice();
          this.state = options.state.slice();
          this.minLoadFactor = options.minLoadFactor;
          this.maxLoadFactor = options.maxLoadFactor;
          this.distinct = options.distinct;
          this.freeEntries = options.freeEntries;
          this.lowWaterMark = options.lowWaterMark;
          this.highWaterMark = options.maxLoadFactor;
          return;
        }

        const initialCapacity = options.initialCapacity === undefined ? defaultInitialCapacity : options.initialCapacity;

        if (initialCapacity < 0) {
          throw new RangeError(`initial capacity must not be less than zero: ${initialCapacity}`);
        }

        const minLoadFactor = options.minLoadFactor === undefined ? defaultMinLoadFactor : options.minLoadFactor;
        const maxLoadFactor = options.maxLoadFactor === undefined ? defaultMaxLoadFactor : options.maxLoadFactor;

        if (minLoadFactor < 0 || minLoadFactor >= 1) {
          throw new RangeError(`invalid minLoadFactor: ${minLoadFactor}`);
        }

        if (maxLoadFactor <= 0 || maxLoadFactor >= 1) {
          throw new RangeError(`invalid maxLoadFactor: ${maxLoadFactor}`);
        }

        if (minLoadFactor >= maxLoadFactor) {
          throw new RangeError(`minLoadFactor (${minLoadFactor}) must be smaller than maxLoadFactor (${maxLoadFactor})`);
        }

        let capacity = initialCapacity; // User wants to put at least capacity elements. We need to choose the size based on the maxLoadFactor to
        // avoid the need to rehash before this capacity is reached.
        // actualCapacity * maxLoadFactor >= capacity

        capacity = capacity / maxLoadFactor | 0;
        capacity = nextPrime(capacity);
        if (capacity === 0) capacity = 1;
        this.table = newArray(capacity);
        this.values = newArray(capacity);
        this.state = newArray(capacity);
        this.minLoadFactor = minLoadFactor;

        if (capacity === largestPrime) {
          this.maxLoadFactor = 1;
        } else {
          this.maxLoadFactor = maxLoadFactor;
        }

        this.distinct = 0;
        this.freeEntries = capacity;
        this.lowWaterMark = 0;
        this.highWaterMark = chooseHighWaterMark(capacity, this.maxLoadFactor);
      }

      clone() {
        return new HashTable(this);
      }

      get size() {
        return this.distinct;
      }

      get(key) {
        const i = this.indexOfKey(key);
        if (i < 0) return 0;
        return this.values[i];
      }

      set(key, value) {
        let i = this.indexOfInsertion(key);

        if (i < 0) {
          i = -i - 1;
          this.values[i] = value;
          return false;
        }

        if (this.distinct > this.highWaterMark) {
          const newCapacity = chooseGrowCapacity(this.distinct + 1, this.minLoadFactor, this.maxLoadFactor);
          this.rehash(newCapacity);
          return this.set(key, value);
        }

        this.table[i] = key;
        this.values[i] = value;
        if (this.state[i] === FREE) this.freeEntries--;
        this.state[i] = FULL;
        this.distinct++;

        if (this.freeEntries < 1) {
          const newCapacity = chooseGrowCapacity(this.distinct + 1, this.minLoadFactor, this.maxLoadFactor);
          this.rehash(newCapacity);
        }

        return true;
      }

      remove(key, noRehash) {
        const i = this.indexOfKey(key);
        if (i < 0) return false;
        this.state[i] = REMOVED;
        this.distinct--;
        if (!noRehash) this.maybeShrinkCapacity();
        return true;
      }

      delete(key, noRehash) {
        const i = this.indexOfKey(key);
        if (i < 0) return false;
        this.state[i] = FREE;
        this.distinct--;
        if (!noRehash) this.maybeShrinkCapacity();
        return true;
      }

      maybeShrinkCapacity() {
        if (this.distinct < this.lowWaterMark) {
          const newCapacity = chooseShrinkCapacity(this.distinct, this.minLoadFactor, this.maxLoadFactor);
          this.rehash(newCapacity);
        }
      }

      containsKey(key) {
        return this.indexOfKey(key) >= 0;
      }

      indexOfKey(key) {
        const table = this.table;
        const state = this.state;
        const length = this.table.length;
        const hash = key & 0x7fffffff;
        let i = hash % length;
        let decrement = hash % (length - 2);
        if (decrement === 0) decrement = 1;

        while (state[i] !== FREE && (state[i] === REMOVED || table[i] !== key)) {
          i -= decrement;
          if (i < 0) i += length;
        }

        if (state[i] === FREE) return -1;
        return i;
      }

      containsValue(value) {
        return this.indexOfValue(value) >= 0;
      }

      indexOfValue(value) {
        const values = this.values;
        const state = this.state;

        for (var i = 0; i < state.length; i++) {
          if (state[i] === FULL && values[i] === value) {
            return i;
          }
        }

        return -1;
      }

      indexOfInsertion(key) {
        const table = this.table;
        const state = this.state;
        const length = table.length;
        const hash = key & 0x7fffffff;
        let i = hash % length;
        let decrement = hash % (length - 2);
        if (decrement === 0) decrement = 1;

        while (state[i] === FULL && table[i] !== key) {
          i -= decrement;
          if (i < 0) i += length;
        }

        if (state[i] === REMOVED) {
          const j = i;

          while (state[i] !== FREE && (state[i] === REMOVED || table[i] !== key)) {
            i -= decrement;
            if (i < 0) i += length;
          }

          if (state[i] === FREE) i = j;
        }

        if (state[i] === FULL) {
          return -i - 1;
        }

        return i;
      }

      ensureCapacity(minCapacity) {
        if (this.table.length < minCapacity) {
          const newCapacity = nextPrime(minCapacity);
          this.rehash(newCapacity);
        }
      }

      rehash(newCapacity) {
        const oldCapacity = this.table.length;
        if (newCapacity <= this.distinct) throw new Error('Unexpected');
        const oldTable = this.table;
        const oldValues = this.values;
        const oldState = this.state;
        const newTable = newArray(newCapacity);
        const newValues = newArray(newCapacity);
        const newState = newArray(newCapacity);
        this.lowWaterMark = chooseLowWaterMark(newCapacity, this.minLoadFactor);
        this.highWaterMark = chooseHighWaterMark(newCapacity, this.maxLoadFactor);
        this.table = newTable;
        this.values = newValues;
        this.state = newState;
        this.freeEntries = newCapacity - this.distinct;

        for (var i = 0; i < oldCapacity; i++) {
          if (oldState[i] === FULL) {
            var element = oldTable[i];
            var index = this.indexOfInsertion(element);
            newTable[index] = element;
            newValues[index] = oldValues[i];
            newState[index] = FULL;
          }
        }
      }

      forEachKey(callback) {
        for (var i = 0; i < this.state.length; i++) {
          if (this.state[i] === FULL) {
            if (!callback(this.table[i])) return false;
          }
        }

        return true;
      }

      forEachValue(callback) {
        for (var i = 0; i < this.state.length; i++) {
          if (this.state[i] === FULL) {
            if (!callback(this.values[i])) return false;
          }
        }

        return true;
      }

      forEachPair(callback) {
        for (var i = 0; i < this.state.length; i++) {
          if (this.state[i] === FULL) {
            if (!callback(this.table[i], this.values[i])) return false;
          }
        }

        return true;
      }

    }

    function chooseLowWaterMark(capacity, minLoad) {
      return capacity * minLoad | 0;
    }

    function chooseHighWaterMark(capacity, maxLoad) {
      return Math.min(capacity - 2, capacity * maxLoad | 0);
    }

    function chooseGrowCapacity(size, minLoad, maxLoad) {
      return nextPrime(Math.max(size + 1, 4 * size / (3 * minLoad + maxLoad) | 0));
    }

    function chooseShrinkCapacity(size, minLoad, maxLoad) {
      return nextPrime(Math.max(size + 1, 4 * size / (minLoad + 3 * maxLoad) | 0));
    }

    function newArray(size) {
      return Array(size).fill(0);
    }

    /* eslint-disable no-eval */
    class SparseMatrix {
      constructor(rows, columns) {
        let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

        if (rows instanceof SparseMatrix) {
          // clone
          const other = rows;

          this._init(other.rows, other.columns, other.elements.clone(), other.threshold);

          return;
        }

        if (Array.isArray(rows)) {
          const matrix = rows;
          rows = matrix.length;
          options = columns || {};
          columns = matrix[0].length;

          this._init(rows, columns, new HashTable(options), options.threshold);

          for (let i = 0; i < rows; i++) {
            for (let j = 0; j < columns; j++) {
              let value = matrix[i][j];
              if (this.threshold && Math.abs(value) < this.threshold) value = 0;

              if (value !== 0) {
                this.elements.set(i * columns + j, matrix[i][j]);
              }
            }
          }
        } else {
          this._init(rows, columns, new HashTable(options), options.threshold);
        }
      }

      _init(rows, columns, elements, threshold) {
        this.rows = rows;
        this.columns = columns;
        this.elements = elements;
        this.threshold = threshold || 0;
      }

      static eye() {
        let rows = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        let columns = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : rows;
        const min = Math.min(rows, columns);
        const matrix = new SparseMatrix(rows, columns, {
          initialCapacity: min
        });

        for (let i = 0; i < min; i++) {
          matrix.set(i, i, 1);
        }

        return matrix;
      }

      clone() {
        return new SparseMatrix(this);
      }

      to2DArray() {
        const copy = new Array(this.rows);

        for (let i = 0; i < this.rows; i++) {
          copy[i] = new Array(this.columns);

          for (let j = 0; j < this.columns; j++) {
            copy[i][j] = this.get(i, j);
          }
        }

        return copy;
      }

      isSquare() {
        return this.rows === this.columns;
      }

      isSymmetric() {
        if (!this.isSquare()) return false;
        let symmetric = true;
        this.forEachNonZero((i, j, v) => {
          if (this.get(j, i) !== v) {
            symmetric = false;
            return false;
          }

          return v;
        });
        return symmetric;
      }
      /**
       * Search for the wither band in the main diagonals
       * @return {number}
       */


      bandWidth() {
        let min = this.columns;
        let max = -1;
        this.forEachNonZero((i, j, v) => {
          let diff = i - j;
          min = Math.min(min, diff);
          max = Math.max(max, diff);
          return v;
        });
        return max - min;
      }
      /**
       * Test if a matrix is consider banded using a threshold
       * @param {number} width
       * @return {boolean}
       */


      isBanded(width) {
        let bandWidth = this.bandWidth();
        return bandWidth <= width;
      }

      get cardinality() {
        return this.elements.size;
      }

      get size() {
        return this.rows * this.columns;
      }

      get(row, column) {
        return this.elements.get(row * this.columns + column);
      }

      set(row, column, value) {
        if (this.threshold && Math.abs(value) < this.threshold) value = 0;

        if (value === 0) {
          this.elements.remove(row * this.columns + column);
        } else {
          this.elements.set(row * this.columns + column, value);
        }

        return this;
      }

      mmul(other) {
        if (this.columns !== other.rows) {
          // eslint-disable-next-line no-console
          console.warn('Number of columns of left matrix are not equal to number of rows of right matrix.');
        }

        const m = this.rows;
        const p = other.columns;
        const result = new SparseMatrix(m, p);
        this.forEachNonZero((i, j, v1) => {
          other.forEachNonZero((k, l, v2) => {
            if (j === k) {
              result.set(i, l, result.get(i, l) + v1 * v2);
            }

            return v2;
          });
          return v1;
        });
        return result;
      }

      kroneckerProduct(other) {
        const m = this.rows;
        const n = this.columns;
        const p = other.rows;
        const q = other.columns;
        const result = new SparseMatrix(m * p, n * q, {
          initialCapacity: this.cardinality * other.cardinality
        });
        this.forEachNonZero((i, j, v1) => {
          other.forEachNonZero((k, l, v2) => {
            result.set(p * i + k, q * j + l, v1 * v2);
            return v2;
          });
          return v1;
        });
        return result;
      }

      forEachNonZero(callback) {
        this.elements.forEachPair((key, value) => {
          const i = key / this.columns | 0;
          const j = key % this.columns;
          let r = callback(i, j, value);
          if (r === false) return false; // stop iteration

          if (this.threshold && Math.abs(r) < this.threshold) r = 0;

          if (r !== value) {
            if (r === 0) {
              this.elements.remove(key, true);
            } else {
              this.elements.set(key, r);
            }
          }

          return true;
        });
        this.elements.maybeShrinkCapacity();
        return this;
      }

      getNonZeros() {
        const cardinality = this.cardinality;
        const rows = new Array(cardinality);
        const columns = new Array(cardinality);
        const values = new Array(cardinality);
        let idx = 0;
        this.forEachNonZero((i, j, value) => {
          rows[idx] = i;
          columns[idx] = j;
          values[idx] = value;
          idx++;
          return value;
        });
        return {
          rows,
          columns,
          values
        };
      }

      setThreshold(newThreshold) {
        if (newThreshold !== 0 && newThreshold !== this.threshold) {
          this.threshold = newThreshold;
          this.forEachNonZero((i, j, v) => v);
        }

        return this;
      }
      /**
       * @return {SparseMatrix} - New transposed sparse matrix
       */


      transpose() {
        let trans = new SparseMatrix(this.columns, this.rows, {
          initialCapacity: this.cardinality
        });
        this.forEachNonZero((i, j, value) => {
          trans.set(j, i, value);
          return value;
        });
        return trans;
      }

      isEmpty() {
        return this.rows === 0 || this.columns === 0;
      }

    }
    SparseMatrix.prototype.klass = 'Matrix';
    SparseMatrix.identity = SparseMatrix.eye;
    SparseMatrix.prototype.tensorProduct = SparseMatrix.prototype.kroneckerProduct;
    /*
     Add dynamically instance and static methods for mathematical operations
     */

    let inplaceOperator = `
(function %name%(value) {
    if (typeof value === 'number') return this.%name%S(value);
    return this.%name%M(value);
})
`;
    let inplaceOperatorScalar = `
(function %name%S(value) {
    this.forEachNonZero((i, j, v) => v %op% value);
    return this;
})
`;
    let inplaceOperatorMatrix = `
(function %name%M(matrix) {
    matrix.forEachNonZero((i, j, v) => {
        this.set(i, j, this.get(i, j) %op% v);
        return v;
    });
    return this;
})
`;
    let staticOperator = `
(function %name%(matrix, value) {
    var newMatrix = new SparseMatrix(matrix);
    return newMatrix.%name%(value);
})
`;
    let inplaceMethod = `
(function %name%() {
    this.forEachNonZero((i, j, v) => %method%(v));
    return this;
})
`;
    let staticMethod = `
(function %name%(matrix) {
    var newMatrix = new SparseMatrix(matrix);
    return newMatrix.%name%();
})
`;
    const operators = [// Arithmetic operators
    ['+', 'add'], ['-', 'sub', 'subtract'], ['*', 'mul', 'multiply'], ['/', 'div', 'divide'], ['%', 'mod', 'modulus'], // Bitwise operators
    ['&', 'and'], ['|', 'or'], ['^', 'xor'], ['<<', 'leftShift'], ['>>', 'signPropagatingRightShift'], ['>>>', 'rightShift', 'zeroFillRightShift']];

    for (const operator of operators) {
      for (let i = 1; i < operator.length; i++) {
        SparseMatrix.prototype[operator[i]] = eval(fillTemplateFunction(inplaceOperator, {
          name: operator[i],
          op: operator[0]
        }));
        SparseMatrix.prototype[`${operator[i]}S`] = eval(fillTemplateFunction(inplaceOperatorScalar, {
          name: `${operator[i]}S`,
          op: operator[0]
        }));
        SparseMatrix.prototype[`${operator[i]}M`] = eval(fillTemplateFunction(inplaceOperatorMatrix, {
          name: `${operator[i]}M`,
          op: operator[0]
        }));
        SparseMatrix[operator[i]] = eval(fillTemplateFunction(staticOperator, {
          name: operator[i]
        }));
      }
    }

    let methods = [['~', 'not']];
    ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cbrt', 'ceil', 'clz32', 'cos', 'cosh', 'exp', 'expm1', 'floor', 'fround', 'log', 'log1p', 'log10', 'log2', 'round', 'sign', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc'].forEach(function (mathMethod) {
      methods.push([`Math.${mathMethod}`, mathMethod]);
    });

    for (const method of methods) {
      for (let i = 1; i < method.length; i++) {
        SparseMatrix.prototype[method[i]] = eval(fillTemplateFunction(inplaceMethod, {
          name: method[i],
          method: method[0]
        }));
        SparseMatrix[method[i]] = eval(fillTemplateFunction(staticMethod, {
          name: method[i]
        }));
      }
    }

    function fillTemplateFunction(template, values) {
      for (const i in values) {
        template = template.replace(new RegExp(`%${i}%`, 'g'), values[i]);
      }

      return template;
    }

    function createPauli(mult) {
      const spin = (mult - 1) / 2;
      const prjs = new Array(mult);
      const temp = new Array(mult);

      for (let i = 0; i < mult; i++) {
        prjs[i] = mult - 1 - i - spin;
        temp[i] = Math.sqrt(spin * (spin + 1) - prjs[i] * (prjs[i] + 1));
      }

      const p = diag(temp, 1, mult, mult);

      for (let i = 0; i < mult; i++) {
        temp[i] = Math.sqrt(spin * (spin + 1) - prjs[i] * (prjs[i] - 1));
      }

      const m = diag(temp, -1, mult, mult);
      const x = p.clone().add(m).mul(0.5);
      const y = m.clone().mul(-1).add(p).mul(-0.5);
      const z = diag(prjs, 0, mult, mult);
      return {
        x,
        y,
        z,
        m,
        p
      };
    }

    function diag(A, d, n, m) {
      const diag = new SparseMatrix(n, m, {
        initialCapacity: 20
      });

      for (let i = 0; i < A.length; i++) {
        if (i - d >= 0 && i - d < n && i < m) {
          diag.set(i - d, i, A[i]);
        }
      }

      return diag;
    }

    const pauli2 = createPauli(2);
    function getPauliMatrix(mult) {
      if (mult === 2) return pauli2;else return createPauli(mult);
    }

    const smallValue = 1e-2;
    function simulateXYPeaks(
    /**
     * The SpinSystem object to be simulated
     */
    spinSystem) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        lineWidth = 1,
        maxClusterSize = 8,
        frequency: frequencyMHz = 400
      } = options;
      const chemicalShifts = spinSystem.chemicalShifts.slice();

      for (let i = 0; i < chemicalShifts.length; i++) {
        chemicalShifts[i] = chemicalShifts[i] * frequencyMHz;
      }

      const multiplicity = spinSystem.multiplicity;
      const xyPeaks = [];

      for (const cluster of spinSystem.clusters) {
        let clusterFake = cluster.map(cluster => cluster < 0 ? -cluster - 1 : cluster);
        let weight = 1;
        let sumI = 0;
        let frequencies = [];
        let intensities = [];

        if (cluster.length > maxClusterSize) {
          // This is a single spin, but the cluster exceeds the maxClusterSize criteria
          // we use the simple multiplicity algorithm
          // Add the central peak. It will be split with every single J coupling.
          let index = 0;

          while (cluster[index++] < 0);

          index = cluster[index - 1];
          frequencies.push(-chemicalShifts[index]);

          for (let i = 0; i < cluster.length; i++) {
            if (cluster[i] < 0) {
              let jc = spinSystem.couplingConstants.get(index, clusterFake[i]) / 2;
              let currentSize = frequencies.length;

              for (let j = 0; j < currentSize; j++) {
                frequencies.push(frequencies[j] + jc);
                frequencies[j] -= jc;
              }
            }
          }

          frequencies.sort((a, b) => a - b);
          sumI = frequencies.length;
          weight = 1;

          for (let i = 0; i < sumI; i++) {
            intensities.push(1);
          }
        } else {
          const hamiltonian = getHamiltonian(chemicalShifts, spinSystem.couplingConstants, multiplicity, spinSystem.connectivity, clusterFake);
          const hamSize = hamiltonian.rows; // TODO: add support for sparse matrix in matrix types.
          // @ts-expect-error sparse matrix not supported

          const evd = new EigenvalueDecomposition(hamiltonian);
          const V = evd.eigenvectorMatrix;
          const diagB = evd.realEigenvalues;
          const assignmentMatrix = new SparseMatrix(hamSize, hamSize);
          const multLen = cluster.length;
          weight = 0;

          for (let n = 0; n < multLen; n++) {
            const L = getPauliMatrix(multiplicity[clusterFake[n]]);
            let temp = 1;

            for (let j = 0; j < n; j++) {
              temp *= multiplicity[clusterFake[j]];
            }

            const A = SparseMatrix.eye(temp);
            temp = 1;

            for (let j = n + 1; j < multLen; j++) {
              temp *= multiplicity[clusterFake[j]];
            }

            const B = SparseMatrix.eye(temp);
            const tempMat = A.kroneckerProduct(L.m).kroneckerProduct(B);

            if (cluster[n] >= 0) {
              assignmentMatrix.add(tempMat.mul(cluster[n] + 1));
              weight++;
            } else {
              assignmentMatrix.add(tempMat.mul(cluster[n]));
            }
          }

          let rhoip = Matrix.zeros(hamSize, hamSize);
          assignmentMatrix.forEachNonZero((i, j, v) => {
            if (v > 0) {
              for (let k = 0; k < V.columns; k++) {
                let element = V.get(j, k);

                if (element !== 0) {
                  rhoip.set(i, k, rhoip.get(i, k) + element);
                }
              }
            }

            return v;
          });
          let rhoip2 = rhoip.clone();
          assignmentMatrix.forEachNonZero((i, j, v) => {
            if (v < 0) {
              for (let k = 0; k < V.columns; k++) {
                let element = V.get(j, k);

                if (element !== 0) {
                  rhoip2.set(i, k, rhoip2.get(i, k) + element);
                }
              }
            }

            return v;
          });
          const tV = V.transpose();
          rhoip = tV.mmul(rhoip);
          const sparseRhoip = new SparseMatrix(rhoip.to2DArray(), {
            threshold: smallValue
          });
          triuTimesAbs(sparseRhoip, smallValue);
          rhoip2 = tV.mmul(rhoip2);
          const sparseRhoip2 = new SparseMatrix(rhoip2.to2DArray(), {
            threshold: smallValue
          });
          sparseRhoip2.forEachNonZero((i, j, v) => {
            return v;
          });
          triuTimesAbs(sparseRhoip2, smallValue);
          sparseRhoip2.forEachNonZero((i, j, v) => {
            let val = rhoip.get(i, j);
            val = Math.min(Math.abs(val), Math.abs(v));
            val *= val;
            sumI += val;
            let valFreq = diagB[i] - diagB[j];
            let insertIn = binarySearch$1(frequencies, valFreq, (a, b) => a - b);

            if (insertIn < 0) {
              frequencies.splice(-1 - insertIn, 0, valFreq);
              intensities.splice(-1 - insertIn, 0, val);
            } else {
              intensities[insertIn] += val;
            }
          });
        }

        const numFreq = frequencies.length;

        if (numFreq > 0) {
          weight /= sumI;
          const diff = lineWidth / 64;
          let valFreq = frequencies[0];
          let inte = intensities[0];
          let count = 1;

          for (let i = 1; i < numFreq; i++) {
            if (Math.abs(frequencies[i] - valFreq / count) < diff) {
              inte += intensities[i];
              valFreq += frequencies[i];
              count++;
            } else {
              xyPeaks.push({
                x: -valFreq / count / frequencyMHz,
                y: inte * weight
              });
              valFreq = frequencies[i];
              inte = intensities[i];
              count = 1;
            }
          }

          xyPeaks.push({
            x: -valFreq / count / frequencyMHz,
            y: inte * weight
          });
        }
      }

      return xyPeaks.filter(peak => peak.x < 1000);
    }

    function triuTimesAbs(A, val) {
      A.forEachNonZero((i, j, v) => {
        if (i > j) return 0;
        if (Math.abs(v) <= val) return 0;
        return v;
      });
    }
    /**
     * Create a hamiltonian matrix for the given spinsystem
     * @param {Array} chemicalShifts - An array containing the chemical shift in Hz
     * @param {Array} couplingConstants - An array containing the coupling constants in Hz
     * @param {Array} multiplicity - An array specifiying the multiplicities of each scalar coupling
     * @param {Array} conMatrix - A one step connectivity matrix for the given spin system
     * @param {Array} cluster - An binary array specifiying the spins to be considered for this hamiltonial
     * @return {object}
     */


    function getHamiltonian(chemicalShifts, couplingConstants, multiplicity, conMatrix, cluster) {
      let hamSize = 1;

      for (const element of cluster) {
        hamSize *= multiplicity[element];
      }

      const clusterHam = new SparseMatrix(hamSize, hamSize);

      for (let pos = 0; pos < cluster.length; pos++) {
        let n = cluster[pos];
        const L = getPauliMatrix(multiplicity[n]);
        let A1, B1;
        let temp = 1;

        for (let i = 0; i < pos; i++) {
          temp *= multiplicity[cluster[i]];
        }

        A1 = SparseMatrix.eye(temp);
        temp = 1;

        for (let i = pos + 1; i < cluster.length; i++) {
          temp *= multiplicity[cluster[i]];
        }

        B1 = SparseMatrix.eye(temp);
        const alpha = chemicalShifts[n];
        const kronProd = A1.kroneckerProduct(L.z).kroneckerProduct(B1);
        clusterHam.add(kronProd.mul(alpha));

        for (let pos2 = 0; pos2 < cluster.length; pos2++) {
          const k = cluster[pos2];

          if (conMatrix.get(n, k) === 1) {
            const S = getPauliMatrix(multiplicity[k]);
            let A2, B2;
            let temp = 1;

            for (let i = 0; i < pos2; i++) {
              temp *= multiplicity[cluster[i]];
            }

            A2 = SparseMatrix.eye(temp);
            temp = 1;

            for (let i = pos2 + 1; i < cluster.length; i++) {
              temp *= multiplicity[cluster[i]];
            }

            B2 = SparseMatrix.eye(temp);
            const kron1 = A1.kroneckerProduct(L.x).kroneckerProduct(B1).mmul(A2.kroneckerProduct(S.x).kroneckerProduct(B2));
            kron1.add(A1.kroneckerProduct(L.y).kroneckerProduct(B1).mul(-1).mmul(A2.kroneckerProduct(S.y).kroneckerProduct(B2)));
            kron1.add(A1.kroneckerProduct(L.z).kroneckerProduct(B1).mmul(A2.kroneckerProduct(S.z).kroneckerProduct(B2)));
            clusterHam.add(kron1.mul(couplingConstants.get(n, k) / 2));
          }
        }
      }

      return clusterHam;
    }

    /**
     * This function simulates a one dimensional nmr spectrum. This function returns an array containing the relative intensities of the spectrum in the specified simulation window (from-to).
     */

    function simulate1D(
    /**
     * The SpinSystem object to be simulated
     */
    spinSystem) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        lineWidth = 1,
        frequency: frequencyMHz = 400,
        from = 0,
        to = 10,
        nbPoints = 1024,
        shape = {
          kind: 'gaussian'
        }
      } = options;
      let peakWidth = lineWidth / frequencyMHz;
      const xyPeaks = simulateXYPeaks(spinSystem, options);
      return generateSpectrum(xyPeaks, {
        generator: {
          from,
          to,
          nbPoints
        },
        peakOptions: {
          shape,
          width: peakWidth
        }
      });
    }

    function splitSpinSystem(spinSystem) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        chemicalShifts,
        couplingConstants,
        connectivity
      } = spinSystem;
      let {
        frequency = 400,
        maxClusterSize = 8
      } = options;
      let betas = calculateBetas(chemicalShifts, couplingConstants, frequency);
      let initClusters = agnes(betas, {
        method: 'single',
        isDistanceMatrix: true
      });
      let clusterList = [];
      let nSpins = chemicalShifts.length;
      splitCluster(initClusters, clusterList, {
        maxClusterSize,
        force: false,
        nSpins,
        connectivity
      });
      let mergedClusters = mergeClusters(clusterList, maxClusterSize);
      let nClusters = mergedClusters.length;
      let clusters = new Array(nClusters);

      for (let j = 0; j < nClusters; j++) {
        clusters[j] = [];

        for (let i = 0; i < nSpins; i++) {
          let element = mergedClusters[j][i];
          if (element === 0) continue;
          clusters[j].push(element < 0 ? -(i + 1) : i);
        }
      }

      return clusters;
    }

    function splitCluster(cluster, clusterList, options) {
      let {
        maxClusterSize,
        force,
        nSpins,
        connectivity
      } = options;

      if (!force && cluster.size <= maxClusterSize) {
        clusterList.push(getMembers(cluster.indices(), nSpins));
      } else {
        for (let child of cluster.children) {
          if (child.size <= maxClusterSize) {
            let members = getMembers(child.indices(), nSpins); // Add the neighbors that shares at least 1 coupling with the given cluster

            let count = 0;

            for (let i = 0; i < nSpins; i++) {
              if (members[i] === 1) {
                for (let j = 0; j < nSpins; j++) {
                  if (connectivity.get(i, j) === 1 && members[j] === 0) {
                    members[j] = -1;
                    count++;
                  }
                }

                count++;
              }
            }

            if (count <= maxClusterSize) {
              clusterList.push(members);
            } else if (child.index < 0) {
              splitCluster(child, clusterList, {
                maxClusterSize,
                force: true,
                nSpins,
                connectivity
              });
            } else {
              // We have to threat this spin alone and use the resurrection algorithm instead of the simulation
              members[child.index] = 2;
              clusterList.push(members);
            }
          } else {
            splitCluster(child, clusterList, {
              maxClusterSize,
              force: false,
              nSpins,
              connectivity
            });
          }
        }
      }
    }

    function calculateBetas(chemicalShifts, couplingConstants, frequency) {
      let nRows = couplingConstants.rows;
      let nColumns = couplingConstants.columns;
      let betas = Matrix.zeros(nRows, nRows); // Before clustering, we must add hidden couplingConstants, we could use molecular information if available

      for (let i = 0; i < nRows; i++) {
        for (let j = i; j < nColumns; j++) {
          let element = couplingConstants.get(i, j);

          if (chemicalShifts[i] - chemicalShifts[j] !== 0) {
            let value = 1 - Math.abs(element / ((chemicalShifts[i] - chemicalShifts[j]) * frequency));
            betas.set(i, j, value);
            betas.set(j, i, value);
          } else if (!(i === j || element !== 0)) {
            betas.set(i, j, 1);
            betas.set(j, i, 1);
          }
        }
      }

      return betas.to2DArray();
    }

    function mergeClusters(list, maxClusterSize) {
      for (let i = list.length - 1; i >= 0; i--) {
        let clusterA = list[i];
        let nElements = clusterA.length;
        let index = 0; // Is it a candidate to be merged?

        while (index < nElements && clusterA[index++] !== -1);

        if (index >= nElements) continue;

        for (let j = list.length - 1; j >= i + 1; j--) {
          let clusterB = list[j]; // Do they have common elements?

          let count = 0;
          let common = 0;

          for (let index = 0; index < nElements; index++) {
            if (clusterA[index] * clusterB[index] === -1) common++;
            if (clusterA[index] !== 0 || clusterB[index] !== 0) count++;
          }

          if (common > 0 && count <= maxClusterSize) {
            // Then we can merge those 2 clusters
            for (let index = 0; index < nElements; index++) {
              if (clusterB[index] === 1) {
                clusterA[index] = 1;
              } else if (clusterB[index] === -1 && clusterA[index] !== 1) {
                clusterA[index] = -1;
              }
            }

            list.splice(j, 1);
          }
        }
      }

      return list;
    }

    function getMembers(cluster, nSpins) {
      let members = new Int16Array(nSpins);

      for (let e of cluster) {
        members[e] = 1;
      }

      return members;
    }

    function checkForMandatory(signals) {
      for (const signal of signals) {
        if (!signal.js) throw new Error('There is not js'); // if (!signal.diaID) throw new Error('There is not diaID');

        if (!signal.atoms) throw new Error('There is not atoms');

        for (const j of signal.js) {
          // if (!j.diaID) throw new Error('There is not diaID');
          if (!j.atoms) throw new Error('There is not atoms');
        }
      }
    }
    /**
     * Generate a spectrum from an array of singals
     */


    function signalsToXY(signals) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      checkForMandatory(signals);
      let {
        frequency = 400,
        shape = {
          kind: 'gaussian'
        },
        from = 0,
        to = 10,
        lineWidth = 1,
        nbPoints = 16 * 1024,
        maxValue = 1e8,
        maxClusterSize = 8
      } = options;

      if (signals.length === 0) {
        return {
          x: xSequentialFill({
            from,
            to,
            size: nbPoints
          }),
          y: Array.from(new Float64Array(nbPoints))
        };
      }

      let spinSystem = signalsToSpinSystem(signals);
      spinSystem.clusters = splitSpinSystem(spinSystem, {
        frequency,
        maxClusterSize
      });
      let spectrum = simulate1D(spinSystem, {
        frequency,
        from,
        to,
        nbPoints,
        lineWidth,
        shape
      });

      if (maxValue) {
        spectrum.y = rescale(spectrum.y, {
          max: maxValue
        });
      }

      return spectrum;
    }

    /**
     * calculate the frequency of a nucleus with respect to a reference nucleus
     */

    function getFrequency(
    /**
     * nucleus to calculate the frequency
     */
    nucleus, observedNucleusData) {
      const {
        nucleus: obsNucleus,
        frequency
      } = observedNucleusData;
      checkExistence$1(nucleus, obsNucleus);
      return frequency * gyromagneticRatio[nucleus] / gyromagneticRatio[obsNucleus];
    }

    function checkExistence$1() {
      let nuclei = [];

      for (var _len = arguments.length, nucleus = new Array(_len), _key = 0; _key < _len; _key++) {
        nucleus[_key] = arguments[_key];
      }

      for (const n of nucleus) {
        if (!(n in gyromagneticRatio)) {
          nuclei.push(n);
        }
      }

      if (nuclei.length !== 0) {
        throw new Error(`${nuclei.join(' , ')} is not supported`);
      }
    }

    async function predictAllSpectra(molecule) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        simulation: simulationOptions = {
          oneD: {},
          twoD: {}
        },
        prediction: predictionOptions = {}
      } = options;
      const predictions = await predictAll(molecule, predictionOptions);
      const spectra = [];
      const result = {
        spectra,
        molecules: [{
          molfile: predictions.molfile
        }]
      };
      const oneDOptions = { ...{
          proton: {
            from: 0,
            to: 14
          },
          carbon: {
            from: 0,
            to: 200
          },
          nbPoints: 65536,
          lineWidth: 1
        },
        ...(simulationOptions.oneD || {})
      };
      const twoDOptions = { ...{
          from: {
            x: oneDOptions.proton.from,
            y: oneDOptions.carbon.from
          },
          to: {
            x: oneDOptions.proton.to,
            y: oneDOptions.carbon.to
          },
          nbPoints: {
            x: 1024,
            y: 1024
          }
        },
        ...(simulationOptions.twoD || {})
      };

      for (const experiment in predictions) {
        switch (experiment) {
          case 'carbon':
          case 'proton':
            {
              spectra.push(get1DSpectrum(predictions[experiment], {
                nbPoints: oneDOptions.nbPoints,
                lineWidth: oneDOptions.lineWidth,
                ...oneDOptions[experiment],
                experiment,
                frequency: simulationOptions.frequency
              }));
              break;
            }

          case 'cosy':
          case 'hsqc':
          case 'hmbc':
            {
              spectra.push(get2DSpectrum(predictions[experiment], { ...twoDOptions,
                experiment,
                frequency: simulationOptions.frequency
              }));
              break;
            }
        }
      }

      return result;
    }

    function get2DSpectrum(prediction, options) {
      const {
        signals,
        zones,
        nuclei
      } = prediction;
      const {
        frequency: baseFrequency,
        experiment
      } = options;
      const width = get2DWidth(nuclei);
      const frequency = calculateFrequency(nuclei, baseFrequency);
      const spectrumData = signals2DToZ(signals, { ...options,
        width,
        factor: 3
      });
      const spectrum = {
        data: { ...spectrumData,
          noise: 0.01
        },
        info: {
          nucleus: nuclei,
          originFrequency: frequency,
          baseFrequency: frequency,
          pulseSequence: experiment,
          experiment: '2d'
        },
        zones: {
          values: zones
        }
      };
      return spectrum;
    }

    function get2DWidth(nucleus) {
      return nucleus[0] === nucleus[1] ? 0.02 : {
        x: 0.02,
        y: 0.2133
      };
    }

    function get1DSpectrum(prediction, options) {
      const {
        frequency = 400,
        experiment
      } = options;
      const {
        signals,
        nucleus
      } = prediction;
      const realFrequency = calculateFrequency(nucleus, frequency);
      const {
        x,
        y
      } = signalsToXY(signals, { ...options,
        frequency: realFrequency
      });
      const spectrum = {
        // todo Array.from is temporary for the developement
        data: {
          x: Array.from(x),
          re: Array.from(y),
          im: null
        },
        info: {
          nucleus: prediction.nucleus,
          dimension: 1,
          originFrequency: realFrequency,
          baseFrequency: realFrequency,
          pulseSequence: 'prediction',
          experiment,
          isFt: true
        },
        ranges: {
          values: prediction.ranges
        }
      };
      return spectrum;
    }

    function calculateFrequency(nucleus, frequency) {
      if (typeof nucleus === 'string') {
        return getFrequency(nucleus, {
          nucleus: '1H',
          frequency
        });
      } else if (nucleus[0] === nucleus[1]) {
        return `${frequency},${frequency}`;
      } else {
        return `${frequency},${getFrequency(nucleus[1], {
      nucleus: nucleus[0],
      frequency
    })}`;
      }
    }

    /**
     * Created by acastillo on 9/3/16.
     */


    class TreeSet {
      constructor(compatator) {
        this.length = 0;
        this.elements = [];
        if (compatator) this.compatator = compatator;else this.compatator = function (a, b) {
          return a - b;
        };
      }

      size() {
        return this.elements.length;
      }

      last() {
        return this.elements[this.length - 1];
      }

      first() {
        return this.elements[0];
      }

      isEmpty() {
        return this.size() === 0;
      }

      pollLast() {
        if (this.length > 0) {
          this.length--;
          return this.elements.splice(this.length, 1);
        }

        return null;
      }

      pollFirst() {
        if (this.length > 0) {
          this.length--;
          return this.elements.splice(0, 1);
        }

        return null;
      }

      add(element) {
        let index = this.binarySearch(element);

        if (index < 0) {
          index = -index - 1;
        }

        this.elements.splice(index, 0, element);
        this.length++;
      }
      /**
       * Performs a binary search of value in array
       * @param {number[]} array - Array in which value will be searched. It must be sorted.
       * @param {number} value - Value to search in array
       * @return {number} If value is found, returns its index in array. Otherwise, returns a negative number indicating where the value should be inserted: -(index + 1)
       */


      binarySearch(value) {
        var low = 0;
        var high = this.elements.length - 1;

        while (low <= high) {
          var mid = low + high >>> 1;
          var midValue = this.elements[mid];
          var cmp = this.compatator(midValue, value);

          if (cmp < 0) {
            low = mid + 1;
          } else if (cmp > 0) {
            high = mid - 1;
          } else {
            return mid;
          }
        }

        return -(low + 1);
      }

    }

    var src$1 = TreeSet;
    var TreeSet$1 = src$1;

    function createMapPossibleAssignments(props) {
      const {
        restrictionByCS,
        predictions,
        targets,
        useIntegrationRestriction
      } = props;
      const {
        tolerance: toleranceCS,
        chemicalShiftRestriction
      } = restrictionByCS;
      let errorAbs = Math.abs(toleranceCS);
      const expandMap = {};

      for (const diaID in predictions) {
        let prediction = predictions[diaID];
        if (prediction.error) prediction.error = Math.abs(prediction.error);
        expandMap[diaID] = [];

        if (targets) {
          for (const targetID in targets) {
            let target = targets[targetID];
            const {
              nbAtoms
            } = prediction;
            const {
              integration
            } = target;
            const couldBeAssigned = useIntegrationRestriction ? integration > 0 ? nbAtoms - integration < 1 : true : true;

            if (couldBeAssigned) {
              if (!chemicalShiftRestriction || typeof prediction.delta === 'undefined') {
                // Chemical shift is not a restriction
                expandMap[diaID].push(targetID);
              } else {
                let error = errorAbs;

                if (prediction.error) {
                  error = Math.max(error, prediction.error);
                }

                const delta = target.signals && target.signals.length > 0 ? target.signals[0].delta : (target.to + target.from) / 2;
                let distAfterLimit = Math.abs(prediction.delta - delta - errorAbs);

                if (distAfterLimit < 4 * errorAbs) {
                  expandMap[diaID].push(targetID);
                }
              }
            }
          }
        }

        expandMap[diaID].push('*');
      }

      return expandMap;
    }

    function partialScore$1(partial, options) {
      const {
        useIntegrationRestriction,
        diaIDPeerPossibleAssignment,
        nbAllowedUnAssigned,
        restrictionByCS,
        predictions,
        targets
      } = options;
      const {
        useChemicalShiftScore
      } = restrictionByCS;
      let countStars = 0;
      let totalPartial = partial.length;
      let partialInverse = {};

      for (let i = 0; i < partial.length; i++) {
        const targetID = partial[i];

        if (targetID && targetID !== '*') {

          if (!partialInverse[targetID]) {
            partialInverse[targetID] = [];
          }

          partialInverse[targetID].push(diaIDPeerPossibleAssignment[i]);
        }

        if (targetID === '*') countStars++;
      }

      if (countStars > nbAllowedUnAssigned) return 0;
      const activeDomainOnTarget = Object.keys(partialInverse);

      if (activeDomainOnTarget.length === 0) {
        return 0;
      }

      if (useIntegrationRestriction) {
        for (let targetID of activeDomainOnTarget) {
          let targetToSource = partialInverse[targetID];
          let total = 0;

          for (const diaID of targetToSource) {
            const prediction = predictions[diaID];
            total += prediction.allHydrogens;
          }

          const {
            integration
          } = targets[targetID];

          if (total - integration >= 0.5) {
            return 0;
          }
        }
      } //chemical shift score


      let chemicalShiftScore = useChemicalShiftScore ? chemicalShiftScoring(partial, options) : 1;
      const penaltyByStarts = countStars / totalPartial;
      return chemicalShiftScore - penaltyByStarts;
    }

    function chemicalShiftScoring(partial, options) {
      const {
        tolerance
      } = options.restrictionByCS;
      const {
        diaIDPeerPossibleAssignment,
        predictions,
        targets
      } = options;
      let chemicalShiftScore = 0;
      let count = 0;

      for (let index = 0; index < partial.length; index++) {
        const targetID = partial[index];

        if (targetID && targetID !== '*') {
          count++;
          let diaID = diaIDPeerPossibleAssignment[index];
          let source = predictions[diaID];
          let target = targets[targetID];
          let error = tolerance;

          if (source.error) {
            error = Math.max(source.error, tolerance);
          }

          if (typeof source.delta === 'undefined') {
            // Chemical shift is not a restriction
            chemicalShiftScore += 1;
          } else {
            const delta = target.signals && target.signals.length > 0 ? target.signals[0].delta : (target.to + target.from) / 2;
            let diff = Math.abs(source.delta - delta);

            if (diff < error) {
              chemicalShiftScore += 1;
            } else {
              diff = Math.abs(diff - error);
              chemicalShiftScore += -0.25 / error * diff + 1;
            }
          }
        }
      }

      if (count > 0) {
        chemicalShiftScore /= count;
      }

      return chemicalShiftScore;
    }

    function exploreTreeRec(props, currentIndex, partial, store) {
      const {
        nSources,
        restrictionByCS,
        timeout,
        timeStart,
        maxSolutions,
        targets,
        predictions,
        lowerBoundScore,
        nbAllowedUnAssigned,
        possibleAssignmentMap,
        useIntegrationRestriction,
        diaIDPeerPossibleAssignment
      } = props;
      const currentDate = new Date();

      if (currentDate.getTime() - timeStart > timeout) {
        return store;
      }

      const diaID = diaIDPeerPossibleAssignment[currentIndex];
      const possibleAssignments = possibleAssignmentMap[diaID];

      for (let targetID of possibleAssignments) {
        partial[currentIndex] = targetID;
        let score = partialScore$1(partial, {
          useIntegrationRestriction,
          diaIDPeerPossibleAssignment,
          nbAllowedUnAssigned,
          restrictionByCS,
          predictions,
          targets
        });

        if (score === 0) {
          if (targetID === '*') {
            partial[currentIndex] = null;
          }

          continue;
        }

        if (currentIndex === nSources - 1 && score >= lowerBoundScore) {
          addSolution$1(store, {
            predictions,
            partial,
            score,
            maxSolutions
          });
        } else if (currentIndex < nSources - 1) {
          exploreTreeRec({
            nSources,
            restrictionByCS,
            timeout,
            timeStart,
            maxSolutions,
            targets,
            predictions,
            lowerBoundScore,
            nbAllowedUnAssigned,
            possibleAssignmentMap,
            useIntegrationRestriction,
            diaIDPeerPossibleAssignment
          }, currentIndex + 1, JSON.parse(JSON.stringify(partial)), store);
        }
      }
    }

    function addSolution$1(store, props) {
      let {
        score,
        maxSolutions,
        partial,
        predictions
      } = props;
      score /= doubleAssignmentPenalty$1(partial, predictions);
      store.nSolutions++;
      let solution = {
        assignment: JSON.parse(JSON.stringify(partial)),
        score
      };

      if (store.nSolutions >= maxSolutions) {
        if (solution.score > store.solutions.last().score) {
          store.solutions.pollLast();
          store.solutions.add(solution);
        }
      } else {
        store.solutions.add(solution);
        store.nSolutions++;
      }
    }

    function doubleAssignmentPenalty$1(partial, predictions) {
      const nbSources = Object.keys(predictions).length;
      let assignments = new Set(partial);
      let nbDoubleAssignment = nbSources - assignments.size;
      return nbDoubleAssignment > 0 ? 2 * nbDoubleAssignment : 1;
    }

    const comparator$1 = (a, b) => {
      return b.score - a.score;
    };

    async function buildAssignments$1(props) {
      const {
        restrictionByCS = {},
        useIntegrationRestriction,
        timeout,
        minScore,
        nbAllowedUnAssigned,
        maxSolutions,
        targets,
        joinedSignals
      } = props;
      const {
        tolerance = 1,
        useChemicalShiftScore = false,
        chemicalShiftRestriction = true
      } = restrictionByCS;
      let date = new Date();
      let timeStart = date.getTime();
      let store = {
        solutions: new TreeSet$1(comparator$1),
        nSolutions: 0
      };
      let nSources = joinedSignals.length;
      const predictions = {};

      for (let prediction of joinedSignals) {
        const diaID = prediction.diaIDs[0];
        const index = prediction.atoms[0];
        predictions[diaID] = { ...prediction,
          diaIDIndex: index,
          allHydrogens: prediction.nbAtoms
        };
      }

      const possibleAssignmentMap = createMapPossibleAssignments({
        restrictionByCS: {
          tolerance,
          useChemicalShiftScore,
          chemicalShiftRestriction
        },
        useIntegrationRestriction,
        predictions,
        targets
      });
      const diaIDPeerPossibleAssignment = Object.keys(possibleAssignmentMap);
      let partial = fillPartial$1(nSources);
      store = {
        solutions: new TreeSet$1(comparator$1),
        nSolutions: 0
      };
      exploreTreeRec({
        nSources,
        restrictionByCS: {
          tolerance,
          useChemicalShiftScore,
          chemicalShiftRestriction
        },
        timeout,
        timeStart,
        targets,
        predictions,
        maxSolutions,
        lowerBoundScore: minScore,
        nbAllowedUnAssigned,
        possibleAssignmentMap,
        diaIDPeerPossibleAssignment,
        useIntegrationRestriction
      }, 0, partial, store);
      const assignments = [];

      for (const solution of store.solutions.elements) {
        const {
          assignment,
          score
        } = solution;
        const currentAssignment = JSON.parse(JSON.stringify(targets));

        for (let i = 0; i < assignment.length; i++) {
          let range = currentAssignment[assignment[i]];
          if (!range.diaIDs) range.diaIDs = [];
          if (assignment[i]) range.diaIDs.push(diaIDPeerPossibleAssignment[i]);
        }

        assignments.push({
          score,
          assignment: Object.values(currentAssignment)
        });
      }

      return assignments;
    }

    function fillPartial$1(nSources) {
      let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
      const partial = new Array(nSources);

      for (let i = 0; i < nSources; i++) {
        partial[i] = value;
      }

      return partial;
    }

    function checkAtomsAndDiaIDs$1(signals) {
      for (const signal of signals) {
        if (!signal.atoms) throw new Error('signal has not atoms property');
        if (!signal.diaIDs) throw new Error('signal has not diaIDs property');
        if (!signal.nbAtoms) throw new Error('signal has not nbAtoms property');
      }
    }

    function checkForIntegration(ranges) {
      for (let range of ranges) {
        if (range.integration === undefined) {
          throw new Error('ranges has not integration property');
        }
      }
    }

    async function get1HAssignments(ranges, molecule) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      let {
        restrictionByCS,
        minScore = 1,
        maxSolutions = 10,
        nbAllowedUnAssigned = 0,
        timeout = 6000,
        predictionOptions = {}
      } = options;

      if (!molecule) {
        throw new Error('It is needed a OCL molecule instance to assign');
      }

      molecule.addImplicitHydrogens();
      addDiastereotopicMissingChirality(molecule);
      const {
        joinedSignals
      } = await predictProton(molecule, predictionOptions);
      checkForIntegration(ranges);
      checkAtomsAndDiaIDs$1(joinedSignals);
      const targets = {};

      for (const range of ranges) {
        const {
          id = v4()
        } = range;
        targets[id] = JSON.parse(JSON.stringify(range));
      }

      return buildAssignments$1({
        restrictionByCS,
        timeout,
        minScore,
        nbAllowedUnAssigned,
        maxSolutions,
        targets,
        joinedSignals,
        useIntegrationRestriction: true
      });
    }

    function checkAtomsAndDiaIDs(signals) {
      for (const signal of signals) {
        if (!signal.atoms) throw new Error('signal has not atoms property');
        if (!signal.diaIDs) throw new Error('signal has not diaIDs property');
        if (!signal.nbAtoms) throw new Error('signal has not nbAtoms property');
      }
    }

    function checkIntegration(ranges) {
      for (let range of ranges) {
        if (range.integration === undefined) range.integration = 0;
      }

      return ranges;
    }

    async function get13CAssignments(ranges, molecule) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      let {
        restrictionByCS = {},
        minScore = 1,
        maxSolutions = 10,
        nbAllowedUnAssigned = 0,
        timeout = 6000,
        predictionOptions = {}
      } = options;

      if (!molecule) {
        throw new Error('It is needed a OCL molecule instance to assign');
      }

      addDiastereotopicMissingChirality(molecule);
      const {
        joinedSignals
      } = await predictCarbon(molecule, predictionOptions);
      checkAtomsAndDiaIDs(joinedSignals);
      const copyRanges = checkIntegration(ranges);
      const targets = {};

      for (const range of copyRanges) {
        const {
          id = v4()
        } = range;
        targets[id] = JSON.parse(JSON.stringify(range));
      }

      return buildAssignments$1({
        restrictionByCS,
        timeout,
        minScore,
        nbAllowedUnAssigned,
        maxSolutions,
        targets,
        joinedSignals,
        useIntegrationRestriction: false
      });
    }

    /**
     * Returns the number of atoms per atom type for a given molecular formula.
     *
     * @param {string} mf
     */
    function getAtomCounts(mf) {
      const elements = mf ? mf.match(/[A-Z][a-z]{0,1}/g) : [];
      const counts = {};

      if (elements) {
        elements.forEach(elem => {
          const regex = new RegExp(`(${elem}\\d+)`, 'g');
          const match = regex.exec(mf);
          let count = 1;

          if (match) {
            count = Number(match[0].split(elem)[1]);
          }

          counts[elem] = count;
        });
      }

      return counts;
    }

    /**
     * Returns the array index of a correlation.
     *
     * @param {Values} correlations
     * @param {Correlation} correlation
     */
    function getCorrelationIndex(correlations, correlation) {
      return correlations.findIndex(_correlation => _correlation.id === correlation.id);
    }

    /**
     * Returns all correlations of a certain atom type.
     *
     * @param {Values} correlations
     * @param {string} atomType
     */
    function getCorrelationsByAtomType(correlations, atomType) {
      return correlations ? correlations.filter(correlation => correlation.atomType === atomType) : [];
    }

    /**
     * Builds a state from current values and an optional molecular formula.
     *
     * @param {Values} values
     * @param {string} mf
     */

    function buildState(values, mf) {
      const state = {};
      const atoms = getAtomCounts(mf);
      const atomTypesInCorrelations = values.reduce((array, correlation) => array.includes(correlation.atomType) ? array : array.concat(correlation.atomType), []);
      atomTypesInCorrelations.forEach(atomType => {
        const correlationsAtomType = getCorrelationsByAtomType(values, atomType); // create state for specific atom type only if there is at least one real correlation

        if (correlationsAtomType.some(correlation => !correlation.pseudo)) {
          // create state error
          const stateAtomTypeError = {};
          const atomCount = atoms[atomType];
          let atomCountAtomType = correlationsAtomType.reduce((sum, correlation) => !correlation.pseudo ? sum + correlation.equivalence : sum, 0);

          if (atomType === 'H') {
            // add protons count from pseudo correlations without any pseudo HSQC correlation
            values.forEach(correlation => {
              if (correlation.pseudo && correlation.atomType !== 'H' && correlation.protonsCount.length === 1 && !correlation.link.some(link => link.experimentType === 'hsqc')) {
                atomCountAtomType += correlation.protonsCount[0];
              }
            }); // determine the number of pseudo correlations

            const pseudoCorrelationCount = correlationsAtomType.reduce((sum, correlation) => correlation.pseudo ? sum + 1 : sum, 0); // determine the not attached protons

            const notAttached = correlationsAtomType.reduce((array, correlation) => Object.keys(correlation.attachment).length === 0 ? array.concat(getCorrelationIndex(values, correlation)) : array, []);

            if (notAttached.length > 0) {
              stateAtomTypeError.notAttached = notAttached;
            }

            atomCountAtomType -= notAttached.length - pseudoCorrelationCount;

            if (atomCountAtomType < 0) {
              atomCountAtomType = 0;
            } // determine the ambiguous attached protons


            const ambiguousAttachment = correlationsAtomType.reduce((array, correlation) => Object.keys(correlation.attachment).length > 1 || Object.keys(correlation.attachment).some(otherAtomType => correlation.attachment[otherAtomType].length > 1) ? array.concat(getCorrelationIndex(values, correlation)) : array, []);

            if (ambiguousAttachment.length > 0) {
              stateAtomTypeError.ambiguousAttachment = ambiguousAttachment;
            }
          }

          if (atomCount !== undefined) {
            const outOfLimit = correlationsAtomType.some((correlation, k) => !correlation.pseudo && correlation.atomType === atomType && k >= atomCount);

            if (outOfLimit) {
              stateAtomTypeError.outOfLimit = true;
            }
          }

          const complete = atomCount === undefined ? undefined : atomCountAtomType === atomCount;

          if (complete === false) {
            stateAtomTypeError.incomplete = true;
          }

          state[atomType] = {
            current: atomCountAtomType,
            total: atomCount,
            complete,
            error: stateAtomTypeError
          };
        }
      });
      return state;
    }

    /**
     * Checks if `value` is classified as an `Array` object.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an array, else `false`.
     * @example
     *
     * _.isArray([1, 2, 3]);
     * // => true
     *
     * _.isArray(document.body.children);
     * // => false
     *
     * _.isArray('abc');
     * // => false
     *
     * _.isArray(_.noop);
     * // => false
     */
    var isArray$7 = Array.isArray;
    var isArray_1 = isArray$7;

    /** Detect free variable `global` from Node.js. */
    var freeGlobal$1 = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
    var _freeGlobal = freeGlobal$1;

    var freeGlobal = _freeGlobal;
    /** Detect free variable `self`. */

    var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
    /** Used as a reference to the global object. */

    var root$8 = freeGlobal || freeSelf || Function('return this')();
    var _root = root$8;

    var root$7 = _root;
    /** Built-in value references. */

    var Symbol$6 = root$7.Symbol;
    var _Symbol = Symbol$6;

    var Symbol$5 = _Symbol;
    /** Used for built-in method references. */

    var objectProto$e = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$b = objectProto$e.hasOwnProperty;
    /**
     * Used to resolve the
     * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
     * of values.
     */

    var nativeObjectToString$1 = objectProto$e.toString;
    /** Built-in value references. */

    var symToStringTag$1 = Symbol$5 ? Symbol$5.toStringTag : undefined;
    /**
     * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
     *
     * @private
     * @param {*} value The value to query.
     * @returns {string} Returns the raw `toStringTag`.
     */

    function getRawTag$1(value) {
      var isOwn = hasOwnProperty$b.call(value, symToStringTag$1),
          tag = value[symToStringTag$1];

      try {
        value[symToStringTag$1] = undefined;
        var unmasked = true;
      } catch (e) {}

      var result = nativeObjectToString$1.call(value);

      if (unmasked) {
        if (isOwn) {
          value[symToStringTag$1] = tag;
        } else {
          delete value[symToStringTag$1];
        }
      }

      return result;
    }

    var _getRawTag = getRawTag$1;

    /** Used for built-in method references. */
    var objectProto$d = Object.prototype;
    /**
     * Used to resolve the
     * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
     * of values.
     */

    var nativeObjectToString = objectProto$d.toString;
    /**
     * Converts `value` to a string using `Object.prototype.toString`.
     *
     * @private
     * @param {*} value The value to convert.
     * @returns {string} Returns the converted string.
     */

    function objectToString$1(value) {
      return nativeObjectToString.call(value);
    }

    var _objectToString = objectToString$1;

    var Symbol$4 = _Symbol,
        getRawTag = _getRawTag,
        objectToString = _objectToString;
    /** `Object#toString` result references. */

    var nullTag = '[object Null]',
        undefinedTag = '[object Undefined]';
    /** Built-in value references. */

    var symToStringTag = Symbol$4 ? Symbol$4.toStringTag : undefined;
    /**
     * The base implementation of `getTag` without fallbacks for buggy environments.
     *
     * @private
     * @param {*} value The value to query.
     * @returns {string} Returns the `toStringTag`.
     */

    function baseGetTag$5(value) {
      if (value == null) {
        return value === undefined ? undefinedTag : nullTag;
      }

      return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value);
    }

    var _baseGetTag = baseGetTag$5;

    /**
     * Checks if `value` is object-like. A value is object-like if it's not `null`
     * and has a `typeof` result of "object".
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
     * @example
     *
     * _.isObjectLike({});
     * // => true
     *
     * _.isObjectLike([1, 2, 3]);
     * // => true
     *
     * _.isObjectLike(_.noop);
     * // => false
     *
     * _.isObjectLike(null);
     * // => false
     */

    function isObjectLike$7(value) {
      return value != null && typeof value == 'object';
    }

    var isObjectLike_1 = isObjectLike$7;

    var baseGetTag$4 = _baseGetTag,
        isObjectLike$6 = isObjectLike_1;
    /** `Object#toString` result references. */

    var symbolTag$3 = '[object Symbol]';
    /**
     * Checks if `value` is classified as a `Symbol` primitive or object.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
     * @example
     *
     * _.isSymbol(Symbol.iterator);
     * // => true
     *
     * _.isSymbol('abc');
     * // => false
     */

    function isSymbol$3(value) {
      return typeof value == 'symbol' || isObjectLike$6(value) && baseGetTag$4(value) == symbolTag$3;
    }

    var isSymbol_1 = isSymbol$3;

    var isArray$6 = isArray_1,
        isSymbol$2 = isSymbol_1;
    /** Used to match property names within property paths. */

    var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
        reIsPlainProp = /^\w*$/;
    /**
     * Checks if `value` is a property name and not a property path.
     *
     * @private
     * @param {*} value The value to check.
     * @param {Object} [object] The object to query keys on.
     * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
     */

    function isKey$1(value, object) {
      if (isArray$6(value)) {
        return false;
      }

      var type = typeof value;

      if (type == 'number' || type == 'symbol' || type == 'boolean' || value == null || isSymbol$2(value)) {
        return true;
      }

      return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || object != null && value in Object(object);
    }

    var _isKey = isKey$1;

    /**
     * Checks if `value` is the
     * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
     * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an object, else `false`.
     * @example
     *
     * _.isObject({});
     * // => true
     *
     * _.isObject([1, 2, 3]);
     * // => true
     *
     * _.isObject(_.noop);
     * // => true
     *
     * _.isObject(null);
     * // => false
     */

    function isObject$5(value) {
      var type = typeof value;
      return value != null && (type == 'object' || type == 'function');
    }

    var isObject_1 = isObject$5;

    var baseGetTag$3 = _baseGetTag,
        isObject$4 = isObject_1;
    /** `Object#toString` result references. */

    var asyncTag = '[object AsyncFunction]',
        funcTag$2 = '[object Function]',
        genTag$1 = '[object GeneratorFunction]',
        proxyTag = '[object Proxy]';
    /**
     * Checks if `value` is classified as a `Function` object.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a function, else `false`.
     * @example
     *
     * _.isFunction(_);
     * // => true
     *
     * _.isFunction(/abc/);
     * // => false
     */

    function isFunction$2(value) {
      if (!isObject$4(value)) {
        return false;
      } // The use of `Object#toString` avoids issues with the `typeof` operator
      // in Safari 9 which returns 'object' for typed arrays and other constructors.


      var tag = baseGetTag$3(value);
      return tag == funcTag$2 || tag == genTag$1 || tag == asyncTag || tag == proxyTag;
    }

    var isFunction_1 = isFunction$2;

    var root$6 = _root;
    /** Used to detect overreaching core-js shims. */

    var coreJsData$1 = root$6['__core-js_shared__'];
    var _coreJsData = coreJsData$1;

    var coreJsData = _coreJsData;
    /** Used to detect methods masquerading as native. */

    var maskSrcKey = function () {
      var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
      return uid ? 'Symbol(src)_1.' + uid : '';
    }();
    /**
     * Checks if `func` has its source masked.
     *
     * @private
     * @param {Function} func The function to check.
     * @returns {boolean} Returns `true` if `func` is masked, else `false`.
     */


    function isMasked$1(func) {
      return !!maskSrcKey && maskSrcKey in func;
    }

    var _isMasked = isMasked$1;

    /** Used for built-in method references. */
    var funcProto$1 = Function.prototype;
    /** Used to resolve the decompiled source of functions. */

    var funcToString$1 = funcProto$1.toString;
    /**
     * Converts `func` to its source code.
     *
     * @private
     * @param {Function} func The function to convert.
     * @returns {string} Returns the source code.
     */

    function toSource$2(func) {
      if (func != null) {
        try {
          return funcToString$1.call(func);
        } catch (e) {}

        try {
          return func + '';
        } catch (e) {}
      }

      return '';
    }

    var _toSource = toSource$2;

    var isFunction$1 = isFunction_1,
        isMasked = _isMasked,
        isObject$3 = isObject_1,
        toSource$1 = _toSource;
    /**
     * Used to match `RegExp`
     * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
     */

    var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
    /** Used to detect host constructors (Safari). */

    var reIsHostCtor = /^\[object .+?Constructor\]$/;
    /** Used for built-in method references. */

    var funcProto = Function.prototype,
        objectProto$c = Object.prototype;
    /** Used to resolve the decompiled source of functions. */

    var funcToString = funcProto.toString;
    /** Used to check objects for own properties. */

    var hasOwnProperty$a = objectProto$c.hasOwnProperty;
    /** Used to detect if a method is native. */

    var reIsNative = RegExp('^' + funcToString.call(hasOwnProperty$a).replace(reRegExpChar, '\\$&').replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$');
    /**
     * The base implementation of `_.isNative` without bad shim checks.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a native function,
     *  else `false`.
     */

    function baseIsNative$1(value) {
      if (!isObject$3(value) || isMasked(value)) {
        return false;
      }

      var pattern = isFunction$1(value) ? reIsNative : reIsHostCtor;
      return pattern.test(toSource$1(value));
    }

    var _baseIsNative = baseIsNative$1;

    /**
     * Gets the value at `key` of `object`.
     *
     * @private
     * @param {Object} [object] The object to query.
     * @param {string} key The key of the property to get.
     * @returns {*} Returns the property value.
     */

    function getValue$1(object, key) {
      return object == null ? undefined : object[key];
    }

    var _getValue = getValue$1;

    var baseIsNative = _baseIsNative,
        getValue = _getValue;
    /**
     * Gets the native function at `key` of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {string} key The key of the method to get.
     * @returns {*} Returns the function if it's native, else `undefined`.
     */

    function getNative$7(object, key) {
      var value = getValue(object, key);
      return baseIsNative(value) ? value : undefined;
    }

    var _getNative = getNative$7;

    var getNative$6 = _getNative;
    /* Built-in method references that are verified to be native. */

    var nativeCreate$4 = getNative$6(Object, 'create');
    var _nativeCreate = nativeCreate$4;

    var nativeCreate$3 = _nativeCreate;
    /**
     * Removes all key-value entries from the hash.
     *
     * @private
     * @name clear
     * @memberOf Hash
     */

    function hashClear$1() {
      this.__data__ = nativeCreate$3 ? nativeCreate$3(null) : {};
      this.size = 0;
    }

    var _hashClear = hashClear$1;

    /**
     * Removes `key` and its value from the hash.
     *
     * @private
     * @name delete
     * @memberOf Hash
     * @param {Object} hash The hash to modify.
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */

    function hashDelete$1(key) {
      var result = this.has(key) && delete this.__data__[key];
      this.size -= result ? 1 : 0;
      return result;
    }

    var _hashDelete = hashDelete$1;

    var nativeCreate$2 = _nativeCreate;
    /** Used to stand-in for `undefined` hash values. */

    var HASH_UNDEFINED$2 = '__lodash_hash_undefined__';
    /** Used for built-in method references. */

    var objectProto$b = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$9 = objectProto$b.hasOwnProperty;
    /**
     * Gets the hash value for `key`.
     *
     * @private
     * @name get
     * @memberOf Hash
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */

    function hashGet$1(key) {
      var data = this.__data__;

      if (nativeCreate$2) {
        var result = data[key];
        return result === HASH_UNDEFINED$2 ? undefined : result;
      }

      return hasOwnProperty$9.call(data, key) ? data[key] : undefined;
    }

    var _hashGet = hashGet$1;

    var nativeCreate$1 = _nativeCreate;
    /** Used for built-in method references. */

    var objectProto$a = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$8 = objectProto$a.hasOwnProperty;
    /**
     * Checks if a hash value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf Hash
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */

    function hashHas$1(key) {
      var data = this.__data__;
      return nativeCreate$1 ? data[key] !== undefined : hasOwnProperty$8.call(data, key);
    }

    var _hashHas = hashHas$1;

    var nativeCreate = _nativeCreate;
    /** Used to stand-in for `undefined` hash values. */

    var HASH_UNDEFINED$1 = '__lodash_hash_undefined__';
    /**
     * Sets the hash `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf Hash
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the hash instance.
     */

    function hashSet$1(key, value) {
      var data = this.__data__;
      this.size += this.has(key) ? 0 : 1;
      data[key] = nativeCreate && value === undefined ? HASH_UNDEFINED$1 : value;
      return this;
    }

    var _hashSet = hashSet$1;

    var hashClear = _hashClear,
        hashDelete = _hashDelete,
        hashGet = _hashGet,
        hashHas = _hashHas,
        hashSet = _hashSet;
    /**
     * Creates a hash object.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */

    function Hash$1(entries) {
      var index = -1,
          length = entries == null ? 0 : entries.length;
      this.clear();

      while (++index < length) {
        var entry = entries[index];
        this.set(entry[0], entry[1]);
      }
    } // Add methods to `Hash`.


    Hash$1.prototype.clear = hashClear;
    Hash$1.prototype['delete'] = hashDelete;
    Hash$1.prototype.get = hashGet;
    Hash$1.prototype.has = hashHas;
    Hash$1.prototype.set = hashSet;
    var _Hash = Hash$1;

    /**
     * Removes all key-value entries from the list cache.
     *
     * @private
     * @name clear
     * @memberOf ListCache
     */

    function listCacheClear$1() {
      this.__data__ = [];
      this.size = 0;
    }

    var _listCacheClear = listCacheClear$1;

    /**
     * Performs a
     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * comparison between two values to determine if they are equivalent.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
     * @example
     *
     * var object = { 'a': 1 };
     * var other = { 'a': 1 };
     *
     * _.eq(object, object);
     * // => true
     *
     * _.eq(object, other);
     * // => false
     *
     * _.eq('a', 'a');
     * // => true
     *
     * _.eq('a', Object('a'));
     * // => false
     *
     * _.eq(NaN, NaN);
     * // => true
     */

    function eq$3(value, other) {
      return value === other || value !== value && other !== other;
    }

    var eq_1 = eq$3;

    var eq$2 = eq_1;
    /**
     * Gets the index at which the `key` is found in `array` of key-value pairs.
     *
     * @private
     * @param {Array} array The array to inspect.
     * @param {*} key The key to search for.
     * @returns {number} Returns the index of the matched value, else `-1`.
     */

    function assocIndexOf$4(array, key) {
      var length = array.length;

      while (length--) {
        if (eq$2(array[length][0], key)) {
          return length;
        }
      }

      return -1;
    }

    var _assocIndexOf = assocIndexOf$4;

    var assocIndexOf$3 = _assocIndexOf;
    /** Used for built-in method references. */

    var arrayProto = Array.prototype;
    /** Built-in value references. */

    var splice = arrayProto.splice;
    /**
     * Removes `key` and its value from the list cache.
     *
     * @private
     * @name delete
     * @memberOf ListCache
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */

    function listCacheDelete$1(key) {
      var data = this.__data__,
          index = assocIndexOf$3(data, key);

      if (index < 0) {
        return false;
      }

      var lastIndex = data.length - 1;

      if (index == lastIndex) {
        data.pop();
      } else {
        splice.call(data, index, 1);
      }

      --this.size;
      return true;
    }

    var _listCacheDelete = listCacheDelete$1;

    var assocIndexOf$2 = _assocIndexOf;
    /**
     * Gets the list cache value for `key`.
     *
     * @private
     * @name get
     * @memberOf ListCache
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */

    function listCacheGet$1(key) {
      var data = this.__data__,
          index = assocIndexOf$2(data, key);
      return index < 0 ? undefined : data[index][1];
    }

    var _listCacheGet = listCacheGet$1;

    var assocIndexOf$1 = _assocIndexOf;
    /**
     * Checks if a list cache value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf ListCache
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */

    function listCacheHas$1(key) {
      return assocIndexOf$1(this.__data__, key) > -1;
    }

    var _listCacheHas = listCacheHas$1;

    var assocIndexOf = _assocIndexOf;
    /**
     * Sets the list cache `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf ListCache
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the list cache instance.
     */

    function listCacheSet$1(key, value) {
      var data = this.__data__,
          index = assocIndexOf(data, key);

      if (index < 0) {
        ++this.size;
        data.push([key, value]);
      } else {
        data[index][1] = value;
      }

      return this;
    }

    var _listCacheSet = listCacheSet$1;

    var listCacheClear = _listCacheClear,
        listCacheDelete = _listCacheDelete,
        listCacheGet = _listCacheGet,
        listCacheHas = _listCacheHas,
        listCacheSet = _listCacheSet;
    /**
     * Creates an list cache object.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */

    function ListCache$4(entries) {
      var index = -1,
          length = entries == null ? 0 : entries.length;
      this.clear();

      while (++index < length) {
        var entry = entries[index];
        this.set(entry[0], entry[1]);
      }
    } // Add methods to `ListCache`.


    ListCache$4.prototype.clear = listCacheClear;
    ListCache$4.prototype['delete'] = listCacheDelete;
    ListCache$4.prototype.get = listCacheGet;
    ListCache$4.prototype.has = listCacheHas;
    ListCache$4.prototype.set = listCacheSet;
    var _ListCache = ListCache$4;

    var getNative$5 = _getNative,
        root$5 = _root;
    /* Built-in method references that are verified to be native. */

    var Map$4 = getNative$5(root$5, 'Map');
    var _Map = Map$4;

    var Hash = _Hash,
        ListCache$3 = _ListCache,
        Map$3 = _Map;
    /**
     * Removes all key-value entries from the map.
     *
     * @private
     * @name clear
     * @memberOf MapCache
     */

    function mapCacheClear$1() {
      this.size = 0;
      this.__data__ = {
        'hash': new Hash(),
        'map': new (Map$3 || ListCache$3)(),
        'string': new Hash()
      };
    }

    var _mapCacheClear = mapCacheClear$1;

    /**
     * Checks if `value` is suitable for use as unique object key.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
     */

    function isKeyable$1(value) {
      var type = typeof value;
      return type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean' ? value !== '__proto__' : value === null;
    }

    var _isKeyable = isKeyable$1;

    var isKeyable = _isKeyable;
    /**
     * Gets the data for `map`.
     *
     * @private
     * @param {Object} map The map to query.
     * @param {string} key The reference key.
     * @returns {*} Returns the map data.
     */

    function getMapData$4(map, key) {
      var data = map.__data__;
      return isKeyable(key) ? data[typeof key == 'string' ? 'string' : 'hash'] : data.map;
    }

    var _getMapData = getMapData$4;

    var getMapData$3 = _getMapData;
    /**
     * Removes `key` and its value from the map.
     *
     * @private
     * @name delete
     * @memberOf MapCache
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */

    function mapCacheDelete$1(key) {
      var result = getMapData$3(this, key)['delete'](key);
      this.size -= result ? 1 : 0;
      return result;
    }

    var _mapCacheDelete = mapCacheDelete$1;

    var getMapData$2 = _getMapData;
    /**
     * Gets the map value for `key`.
     *
     * @private
     * @name get
     * @memberOf MapCache
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */

    function mapCacheGet$1(key) {
      return getMapData$2(this, key).get(key);
    }

    var _mapCacheGet = mapCacheGet$1;

    var getMapData$1 = _getMapData;
    /**
     * Checks if a map value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf MapCache
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */

    function mapCacheHas$1(key) {
      return getMapData$1(this, key).has(key);
    }

    var _mapCacheHas = mapCacheHas$1;

    var getMapData = _getMapData;
    /**
     * Sets the map `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf MapCache
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the map cache instance.
     */

    function mapCacheSet$1(key, value) {
      var data = getMapData(this, key),
          size = data.size;
      data.set(key, value);
      this.size += data.size == size ? 0 : 1;
      return this;
    }

    var _mapCacheSet = mapCacheSet$1;

    var mapCacheClear = _mapCacheClear,
        mapCacheDelete = _mapCacheDelete,
        mapCacheGet = _mapCacheGet,
        mapCacheHas = _mapCacheHas,
        mapCacheSet = _mapCacheSet;
    /**
     * Creates a map cache object to store key-value pairs.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */

    function MapCache$3(entries) {
      var index = -1,
          length = entries == null ? 0 : entries.length;
      this.clear();

      while (++index < length) {
        var entry = entries[index];
        this.set(entry[0], entry[1]);
      }
    } // Add methods to `MapCache`.


    MapCache$3.prototype.clear = mapCacheClear;
    MapCache$3.prototype['delete'] = mapCacheDelete;
    MapCache$3.prototype.get = mapCacheGet;
    MapCache$3.prototype.has = mapCacheHas;
    MapCache$3.prototype.set = mapCacheSet;
    var _MapCache = MapCache$3;

    var MapCache$2 = _MapCache;
    /** Error message constants. */

    var FUNC_ERROR_TEXT = 'Expected a function';
    /**
     * Creates a function that memoizes the result of `func`. If `resolver` is
     * provided, it determines the cache key for storing the result based on the
     * arguments provided to the memoized function. By default, the first argument
     * provided to the memoized function is used as the map cache key. The `func`
     * is invoked with the `this` binding of the memoized function.
     *
     * **Note:** The cache is exposed as the `cache` property on the memoized
     * function. Its creation may be customized by replacing the `_.memoize.Cache`
     * constructor with one whose instances implement the
     * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
     * method interface of `clear`, `delete`, `get`, `has`, and `set`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to have its output memoized.
     * @param {Function} [resolver] The function to resolve the cache key.
     * @returns {Function} Returns the new memoized function.
     * @example
     *
     * var object = { 'a': 1, 'b': 2 };
     * var other = { 'c': 3, 'd': 4 };
     *
     * var values = _.memoize(_.values);
     * values(object);
     * // => [1, 2]
     *
     * values(other);
     * // => [3, 4]
     *
     * object.a = 2;
     * values(object);
     * // => [1, 2]
     *
     * // Modify the result cache.
     * values.cache.set(object, ['a', 'b']);
     * values(object);
     * // => ['a', 'b']
     *
     * // Replace `_.memoize.Cache`.
     * _.memoize.Cache = WeakMap;
     */

    function memoize$1(func, resolver) {
      if (typeof func != 'function' || resolver != null && typeof resolver != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }

      var memoized = function () {
        var args = arguments,
            key = resolver ? resolver.apply(this, args) : args[0],
            cache = memoized.cache;

        if (cache.has(key)) {
          return cache.get(key);
        }

        var result = func.apply(this, args);
        memoized.cache = cache.set(key, result) || cache;
        return result;
      };

      memoized.cache = new (memoize$1.Cache || MapCache$2)();
      return memoized;
    } // Expose `MapCache`.


    memoize$1.Cache = MapCache$2;
    var memoize_1 = memoize$1;

    var memoize = memoize_1;
    /** Used as the maximum memoize cache size. */

    var MAX_MEMOIZE_SIZE = 500;
    /**
     * A specialized version of `_.memoize` which clears the memoized function's
     * cache when it exceeds `MAX_MEMOIZE_SIZE`.
     *
     * @private
     * @param {Function} func The function to have its output memoized.
     * @returns {Function} Returns the new memoized function.
     */

    function memoizeCapped$1(func) {
      var result = memoize(func, function (key) {
        if (cache.size === MAX_MEMOIZE_SIZE) {
          cache.clear();
        }

        return key;
      });
      var cache = result.cache;
      return result;
    }

    var _memoizeCapped = memoizeCapped$1;

    var memoizeCapped = _memoizeCapped;
    /** Used to match property names within property paths. */

    var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
    /** Used to match backslashes in property paths. */

    var reEscapeChar = /\\(\\)?/g;
    /**
     * Converts `string` to a property path array.
     *
     * @private
     * @param {string} string The string to convert.
     * @returns {Array} Returns the property path array.
     */

    var stringToPath$1 = memoizeCapped(function (string) {
      var result = [];

      if (string.charCodeAt(0) === 46
      /* . */
      ) {
        result.push('');
      }

      string.replace(rePropName, function (match, number, quote, subString) {
        result.push(quote ? subString.replace(reEscapeChar, '$1') : number || match);
      });
      return result;
    });
    var _stringToPath = stringToPath$1;

    /**
     * A specialized version of `_.map` for arrays without support for iteratee
     * shorthands.
     *
     * @private
     * @param {Array} [array] The array to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Array} Returns the new mapped array.
     */

    function arrayMap$1(array, iteratee) {
      var index = -1,
          length = array == null ? 0 : array.length,
          result = Array(length);

      while (++index < length) {
        result[index] = iteratee(array[index], index, array);
      }

      return result;
    }

    var _arrayMap = arrayMap$1;

    var Symbol$3 = _Symbol,
        arrayMap = _arrayMap,
        isArray$5 = isArray_1,
        isSymbol$1 = isSymbol_1;
    /** Used as references for various `Number` constants. */

    var INFINITY$1 = 1 / 0;
    /** Used to convert symbols to primitives and strings. */

    var symbolProto$2 = Symbol$3 ? Symbol$3.prototype : undefined,
        symbolToString = symbolProto$2 ? symbolProto$2.toString : undefined;
    /**
     * The base implementation of `_.toString` which doesn't convert nullish
     * values to empty strings.
     *
     * @private
     * @param {*} value The value to process.
     * @returns {string} Returns the string.
     */

    function baseToString$1(value) {
      // Exit early for strings to avoid a performance hit in some environments.
      if (typeof value == 'string') {
        return value;
      }

      if (isArray$5(value)) {
        // Recursively convert values (susceptible to call stack limits).
        return arrayMap(value, baseToString$1) + '';
      }

      if (isSymbol$1(value)) {
        return symbolToString ? symbolToString.call(value) : '';
      }

      var result = value + '';
      return result == '0' && 1 / value == -INFINITY$1 ? '-0' : result;
    }

    var _baseToString = baseToString$1;

    var baseToString = _baseToString;
    /**
     * Converts `value` to a string. An empty string is returned for `null`
     * and `undefined` values. The sign of `-0` is preserved.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to convert.
     * @returns {string} Returns the converted string.
     * @example
     *
     * _.toString(null);
     * // => ''
     *
     * _.toString(-0);
     * // => '-0'
     *
     * _.toString([1, 2, 3]);
     * // => '1,2,3'
     */

    function toString$1(value) {
      return value == null ? '' : baseToString(value);
    }

    var toString_1 = toString$1;

    var isArray$4 = isArray_1,
        isKey = _isKey,
        stringToPath = _stringToPath,
        toString = toString_1;
    /**
     * Casts `value` to a path array if it's not one.
     *
     * @private
     * @param {*} value The value to inspect.
     * @param {Object} [object] The object to query keys on.
     * @returns {Array} Returns the cast property path array.
     */

    function castPath$1(value, object) {
      if (isArray$4(value)) {
        return value;
      }

      return isKey(value, object) ? [value] : stringToPath(toString(value));
    }

    var _castPath = castPath$1;

    var isSymbol = isSymbol_1;
    /** Used as references for various `Number` constants. */

    var INFINITY = 1 / 0;
    /**
     * Converts `value` to a string key if it's not a string or symbol.
     *
     * @private
     * @param {*} value The value to inspect.
     * @returns {string|symbol} Returns the key.
     */

    function toKey$1(value) {
      if (typeof value == 'string' || isSymbol(value)) {
        return value;
      }

      var result = value + '';
      return result == '0' && 1 / value == -INFINITY ? '-0' : result;
    }

    var _toKey = toKey$1;

    var castPath = _castPath,
        toKey = _toKey;
    /**
     * The base implementation of `_.get` without support for default values.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {Array|string} path The path of the property to get.
     * @returns {*} Returns the resolved value.
     */

    function baseGet$1(object, path) {
      path = castPath(path, object);
      var index = 0,
          length = path.length;

      while (object != null && index < length) {
        object = object[toKey(path[index++])];
      }

      return index && index == length ? object : undefined;
    }

    var _baseGet = baseGet$1;

    var baseGet = _baseGet;
    /**
     * Gets the value at `path` of `object`. If the resolved value is
     * `undefined`, the `defaultValue` is returned in its place.
     *
     * @static
     * @memberOf _
     * @since 3.7.0
     * @category Object
     * @param {Object} object The object to query.
     * @param {Array|string} path The path of the property to get.
     * @param {*} [defaultValue] The value returned for `undefined` resolved values.
     * @returns {*} Returns the resolved value.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
     *
     * _.get(object, 'a[0].b.c');
     * // => 3
     *
     * _.get(object, ['a', '0', 'b', 'c']);
     * // => 3
     *
     * _.get(object, 'a.b.c', 'default');
     * // => 'default'
     */

    function get(object, path, defaultValue) {
      var result = object == null ? undefined : baseGet(object, path);
      return result === undefined ? defaultValue : result;
    }

    var get_1 = get;
    var lodashGet = get_1;

    /**
     * Checks for a numeric match within a certain tolerance.
     *
     * @param {number} value1
     * @param {number} value2
     * @param {number} tolerance
     */
    function checkMatch(value1, value2, tolerance) {
      return value1 - tolerance <= value2 && value2 <= value1 + tolerance;
    }

    function getLinkDim(link) {
      return link.experimentType === '1d' ? 1 : 2;
    }

    function getLinkDelta(link) {
      if (!link.pseudo) {
        return getLinkDim(link) === 1 ? link.signal.delta : link.axis === 'x' ? link.signal.x.delta : link.signal.y.delta;
      }
    }

    function getCorrelationDelta(correlation) {
      if (correlation.link.length > 0) return getLinkDelta(correlation.link[0]);
    }

    /**
     * Sets proton counts from DEPT90 signals and DEPT135/edited HSQC signals.
     *
     * @param {Values} correlations
     * @param {Array<{ delta: number }>} signals90
     * @param {Array<{ delta: number; sign?: number }>} signals135
     * @param {number} toleranceAtomType
     */

    function setProtonsCount(correlations, signals90, signals135, toleranceAtomType) {
      // eslint-disable-next-line @typescript-eslint/prefer-for-of
      for (let i = 0; i < correlations.length; i++) {
        const correlation = correlations[i];

        if (correlation.edited.protonsCount) {
          // do not overwrite a manually edited value
          continue;
        }

        const correlationDelta = getCorrelationDelta(correlation);
        const match = [-1, -1];

        for (let k = 0; k < signals90.length; k++) {
          if ( // signals90[k].sign === 1 &&
          correlationDelta !== undefined && checkMatch(correlationDelta, signals90[k].delta, toleranceAtomType)) {
            match[0] = k;
            break;
          }
        }

        for (let k = 0; k < signals135.length; k++) {
          if (correlationDelta !== undefined && checkMatch(correlationDelta, signals135[k].delta, toleranceAtomType)) {
            match[1] = k;
            break;
          }
        }

        if (match[0] >= 0) {
          // signal match in DEPT90
          // CH
          correlation.protonsCount = [1];
          continue;
        } // no signal match in DEPT90


        if (match[1] >= 0) {
          // signal match in DEPT135
          if (signals135[match[1]].sign === 1) {
            // positive signal
            if (signals90.length > 0) {
              // in case of both DEPT90 and DEPT135 are given
              // CH3
              correlation.protonsCount = [3];
            } else {
              // in case of DEPT135 is given only
              // CH or CH3
              correlation.protonsCount = [1, 3];
            }
          } else {
            // negative signal
            // CH2
            correlation.protonsCount = [2];
          }
        } else if (signals135.length > 0) {
          // no signal match in both spectra
          // qC
          correlation.protonsCount = [0];
        } else {
          // no information
          correlation.protonsCount = [];
        }
      }

      return correlations;
    }

    /**
     * Sets proton counts from DEPT90 signals and DEPT135 signals.
     *
     * @param {Values} correlations
     * @param {Experiment1DSignals} signalsDEPT
     * @param {Tolerance} tolerance
     * @param {string} atomType
     */

    function setProtonsCountFromDEPT(correlations, signalsDEPT, tolerance, atomType) {
      const correlationsAtomType = getCorrelationsByAtomType(correlations, atomType).filter(correlation => !correlation.pseudo);
      const signalsDEPT90 = lodashGet(signalsDEPT, '90', []).filter(signalDEPT90 => signalDEPT90.atomType === atomType).map(signalDEPT90 => signalDEPT90.signal);
      const signalsDEPT135 = lodashGet(signalsDEPT, '135', []).filter(signalDEPT135 => signalDEPT135.atomType === atomType).map(signalDEPT135 => signalDEPT135.signal);
      setProtonsCount(correlationsAtomType, signalsDEPT90, signalsDEPT135, tolerance[atomType]);
      return correlations;
    }

    /**
     * Sets proton counts from edited HSQC signals.
     *
     * @param {Values} correlations
     * @param {Experiment2DSignals} signals2D
     * @param {Tolerance} tolerance
     * @param {string} heavyAtomType
     */

    function setProtonsCountFromEditedHSQC(correlations, signals2D, tolerance, heavyAtomType) {
      const correlationsAtomTypeHSQC = correlations.filter(correlation => !correlation.pseudo && correlation.atomType === heavyAtomType);
      const signalsEditedHSQC = lodashGet(signals2D, 'hsqc', []).filter(signal2D => signal2D.atomType[1] === heavyAtomType && signal2D.signal.sign !== 0).map(signal2D => {
        return {
          delta: signal2D.signal.y.delta,
          sign: signal2D.signal.sign
        };
      });
      setProtonsCount(correlationsAtomTypeHSQC, [], signalsEditedHSQC, tolerance[heavyAtomType]);
      return correlations;
    }

    /**
     * Sets proton counts from DEPT90 and/or DEPT135/edited HSQC signals, depending on what spectra data is given.
     *
     * @param {Values} correlations
     * @param {Experiment1DSignals} signalsDEPT
     * @param {Experiment2DSignals} signals2D
     * @param {Tolerance} tolerance
     */

    function setProtonsCountFromData(correlations, signalsDEPT, signals2D, tolerance) {
      const heavyAtomTypes = [];
      correlations.forEach(correlation => {
        if (!correlation.pseudo && correlation.atomType !== 'H' && !heavyAtomTypes.includes(correlation.atomType)) {
          heavyAtomTypes.push(correlation.atomType);

          if (Object.keys(signalsDEPT).length > 0) {
            setProtonsCountFromDEPT(correlations, signalsDEPT, tolerance, correlation.atomType);
          } else {
            setProtonsCountFromEditedHSQC(correlations, signals2D, tolerance, correlation.atomType);
          }
        }
      });
      return correlations;
    }

    /**
     * Get all different experiments from spectra data.
     *
     * @param {Spectra} spectraData
     */
    function getExperiments(spectraData) {
      if (!spectraData) return {};
      const experiments = {};

      for (const spectrum of spectraData) {
        if (spectrum.info.isFid) continue;

        if (!experiments[`${spectrum.info.dimension}D`]) {
          experiments[`${spectrum.info.dimension}D`] = {};
        }

        const experiment = spectrum.info.experiment;

        if (!experiments[`${spectrum.info.dimension}D`][`${experiment}`]) {
          experiments[`${spectrum.info.dimension}D`][`${experiment}`] = [];
        }

        experiments[`${spectrum.info.dimension}D`][`${experiment}`].push(spectrum);
      }

      return experiments;
    }

    /**
     * Returns the atom type from nucleus.
     * @param {string} nucleus
     */
    function getAtomTypeFromNucleus(nucleus) {
      return nucleus.length > 0 ? nucleus.split(/\d+/)[1] : '';
    }

    /**
     * Add experiment of certain type to experiments.
     *
     * @param {Experiments} experiments
     * @param {ExperimentsType} experimentsType
     * @param {string} type
     * @param {boolean} checkAtomType
     * @param {string} experimentKey
     */

    function addToExperiments(experiments, experimentsType, type, checkAtomType, experimentKey) {
      const _experiments = lodashGet(experiments, `${type}`, []) // don't consider DEPT etc. here
      .filter(_experiment => {
        const hasValues = lodashGet(_experiment, type.includes('1D') ? 'ranges.values' : 'zones.values', []).length > 0;
        return checkAtomType ? getAtomTypeFromNucleus(_experiment.info.nucleus) === experimentKey && hasValues : hasValues;
      });

      if (_experiments.length > 0) {
        experimentsType[experimentKey] = _experiments;
      }
    }

    /**
     * Get "plain" 1D experiments containing ranges, i.e. without DEPT etc..
     *
     * @param {Spectra} spectraData
     */

    function getExperiments1D(experiments) {
      const _experiments1D = {};
      lodashGet(experiments, '1D.1d', []).map(experiment => getAtomTypeFromNucleus(experiment.info.nucleus)).forEach(atomType => {
        addToExperiments(experiments, _experiments1D, '1D.1d', true, atomType);
      });
      return _experiments1D;
    }

    /**
     * Get "extra" 1D experiments containing ranges, e.g. DEPT.
     *
     * @param {Spectra} spectraData
     */

    function getExperiments1DExtra(experiments) {
      const _experiments1DExtra = {};
      Object.keys(lodashGet(experiments, `1D`, {})).filter(experimentType => experimentType !== '1d') // don't consider "plain" 1D experiments here
      .forEach(experimentType => {
        addToExperiments(experiments, _experiments1DExtra, `1D.${experimentType}`, false, experimentType);
      });
      return _experiments1DExtra;
    }

    /**
     * Get 2D experiments containing zones.
     *
     * @param {Spectra} spectraData
     */

    function getExperiments2D(experiments) {
      const _experiments2D = {};
      Object.keys(lodashGet(experiments, '2D', {})).forEach(experimentType => {
        addToExperiments(experiments, _experiments2D, `2D.${experimentType}`, false, experimentType);
      });
      return _experiments2D;
    }

    const allowedSignalKinds = ['signal'];

    /**
     * Get all different 1D signals from experiments with allowed signal kinds in "signalKindsToInclude".
     *
     * @param {ExperimentsType} experiments1D
     */

    function getSignals1D(experiments1D) {
      // store valid signals from 1D experiments
      const signals1DByAtomType = {};

      for (const atomType in experiments1D) {
        const signals = [];
        const experiment = experiments1D[`${atomType}`] || [];
        if (experiment.length === 0) continue;
        const index = 0;
        const spectrum1D = experiment[index];

        for (const range of spectrum1D.ranges.values) {
          for (const signal of range.signals) {
            if (!signal.kind || !allowedSignalKinds.includes(signal.kind)) continue;

            if (!checkExistence(signal, signals)) {
              signals.push({
                experimentType: '1d',
                experimentID: spectrum1D.id,
                integration: signal.integration ? signal.integration : range.integration,
                atomType,
                signal: { ...signal
                }
              });
            }
          }
        }

        signals1DByAtomType[atomType] = signals;
      }

      return signals1DByAtomType;
    }

    function checkExistence(current, group) {
      for (const element of group) {
        if (checkMatch(element.signal.delta, current.delta, 0.0)) {
          return true;
        }
      }

      return false;
    }

    var ListCache$2 = _ListCache;
    /**
     * Removes all key-value entries from the stack.
     *
     * @private
     * @name clear
     * @memberOf Stack
     */

    function stackClear$1() {
      this.__data__ = new ListCache$2();
      this.size = 0;
    }

    var _stackClear = stackClear$1;

    /**
     * Removes `key` and its value from the stack.
     *
     * @private
     * @name delete
     * @memberOf Stack
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */

    function stackDelete$1(key) {
      var data = this.__data__,
          result = data['delete'](key);
      this.size = data.size;
      return result;
    }

    var _stackDelete = stackDelete$1;

    /**
     * Gets the stack value for `key`.
     *
     * @private
     * @name get
     * @memberOf Stack
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */

    function stackGet$1(key) {
      return this.__data__.get(key);
    }

    var _stackGet = stackGet$1;

    /**
     * Checks if a stack value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf Stack
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */

    function stackHas$1(key) {
      return this.__data__.has(key);
    }

    var _stackHas = stackHas$1;

    var ListCache$1 = _ListCache,
        Map$2 = _Map,
        MapCache$1 = _MapCache;
    /** Used as the size to enable large array optimizations. */

    var LARGE_ARRAY_SIZE = 200;
    /**
     * Sets the stack `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf Stack
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the stack cache instance.
     */

    function stackSet$1(key, value) {
      var data = this.__data__;

      if (data instanceof ListCache$1) {
        var pairs = data.__data__;

        if (!Map$2 || pairs.length < LARGE_ARRAY_SIZE - 1) {
          pairs.push([key, value]);
          this.size = ++data.size;
          return this;
        }

        data = this.__data__ = new MapCache$1(pairs);
      }

      data.set(key, value);
      this.size = data.size;
      return this;
    }

    var _stackSet = stackSet$1;

    var ListCache = _ListCache,
        stackClear = _stackClear,
        stackDelete = _stackDelete,
        stackGet = _stackGet,
        stackHas = _stackHas,
        stackSet = _stackSet;
    /**
     * Creates a stack cache object to store key-value pairs.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */

    function Stack$2(entries) {
      var data = this.__data__ = new ListCache(entries);
      this.size = data.size;
    } // Add methods to `Stack`.


    Stack$2.prototype.clear = stackClear;
    Stack$2.prototype['delete'] = stackDelete;
    Stack$2.prototype.get = stackGet;
    Stack$2.prototype.has = stackHas;
    Stack$2.prototype.set = stackSet;
    var _Stack = Stack$2;

    /**
     * A specialized version of `_.forEach` for arrays without support for
     * iteratee shorthands.
     *
     * @private
     * @param {Array} [array] The array to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Array} Returns `array`.
     */

    function arrayEach$1(array, iteratee) {
      var index = -1,
          length = array == null ? 0 : array.length;

      while (++index < length) {
        if (iteratee(array[index], index, array) === false) {
          break;
        }
      }

      return array;
    }

    var _arrayEach = arrayEach$1;

    var getNative$4 = _getNative;

    var defineProperty$1 = function () {
      try {
        var func = getNative$4(Object, 'defineProperty');
        func({}, '', {});
        return func;
      } catch (e) {}
    }();

    var _defineProperty = defineProperty$1;

    var defineProperty = _defineProperty;
    /**
     * The base implementation of `assignValue` and `assignMergeValue` without
     * value checks.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {string} key The key of the property to assign.
     * @param {*} value The value to assign.
     */

    function baseAssignValue$2(object, key, value) {
      if (key == '__proto__' && defineProperty) {
        defineProperty(object, key, {
          'configurable': true,
          'enumerable': true,
          'value': value,
          'writable': true
        });
      } else {
        object[key] = value;
      }
    }

    var _baseAssignValue = baseAssignValue$2;

    var baseAssignValue$1 = _baseAssignValue,
        eq$1 = eq_1;
    /** Used for built-in method references. */

    var objectProto$9 = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$7 = objectProto$9.hasOwnProperty;
    /**
     * Assigns `value` to `key` of `object` if the existing value is not equivalent
     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {string} key The key of the property to assign.
     * @param {*} value The value to assign.
     */

    function assignValue$2(object, key, value) {
      var objValue = object[key];

      if (!(hasOwnProperty$7.call(object, key) && eq$1(objValue, value)) || value === undefined && !(key in object)) {
        baseAssignValue$1(object, key, value);
      }
    }

    var _assignValue = assignValue$2;

    var assignValue$1 = _assignValue,
        baseAssignValue = _baseAssignValue;
    /**
     * Copies properties of `source` to `object`.
     *
     * @private
     * @param {Object} source The object to copy properties from.
     * @param {Array} props The property identifiers to copy.
     * @param {Object} [object={}] The object to copy properties to.
     * @param {Function} [customizer] The function to customize copied values.
     * @returns {Object} Returns `object`.
     */

    function copyObject$4(source, props, object, customizer) {
      var isNew = !object;
      object || (object = {});
      var index = -1,
          length = props.length;

      while (++index < length) {
        var key = props[index];
        var newValue = customizer ? customizer(object[key], source[key], key, object, source) : undefined;

        if (newValue === undefined) {
          newValue = source[key];
        }

        if (isNew) {
          baseAssignValue(object, key, newValue);
        } else {
          assignValue$1(object, key, newValue);
        }
      }

      return object;
    }

    var _copyObject = copyObject$4;

    /**
     * The base implementation of `_.times` without support for iteratee shorthands
     * or max array length checks.
     *
     * @private
     * @param {number} n The number of times to invoke `iteratee`.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Array} Returns the array of results.
     */

    function baseTimes$1(n, iteratee) {
      var index = -1,
          result = Array(n);

      while (++index < n) {
        result[index] = iteratee(index);
      }

      return result;
    }

    var _baseTimes = baseTimes$1;

    var baseGetTag$2 = _baseGetTag,
        isObjectLike$5 = isObjectLike_1;
    /** `Object#toString` result references. */

    var argsTag$3 = '[object Arguments]';
    /**
     * The base implementation of `_.isArguments`.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
     */

    function baseIsArguments$1(value) {
      return isObjectLike$5(value) && baseGetTag$2(value) == argsTag$3;
    }

    var _baseIsArguments = baseIsArguments$1;

    var baseIsArguments = _baseIsArguments,
        isObjectLike$4 = isObjectLike_1;
    /** Used for built-in method references. */

    var objectProto$8 = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$6 = objectProto$8.hasOwnProperty;
    /** Built-in value references. */

    var propertyIsEnumerable$1 = objectProto$8.propertyIsEnumerable;
    /**
     * Checks if `value` is likely an `arguments` object.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
     *  else `false`.
     * @example
     *
     * _.isArguments(function() { return arguments; }());
     * // => true
     *
     * _.isArguments([1, 2, 3]);
     * // => false
     */

    var isArguments$1 = baseIsArguments(function () {
      return arguments;
    }()) ? baseIsArguments : function (value) {
      return isObjectLike$4(value) && hasOwnProperty$6.call(value, 'callee') && !propertyIsEnumerable$1.call(value, 'callee');
    };
    var isArguments_1 = isArguments$1;

    var isBuffer$3 = {exports: {}};

    /**
     * This method returns `false`.
     *
     * @static
     * @memberOf _
     * @since 4.13.0
     * @category Util
     * @returns {boolean} Returns `false`.
     * @example
     *
     * _.times(2, _.stubFalse);
     * // => [false, false]
     */

    function stubFalse() {
      return false;
    }

    var stubFalse_1 = stubFalse;

    (function (module, exports) {
      var root = _root,
          stubFalse = stubFalse_1;
      /** Detect free variable `exports`. */

      var freeExports = exports && !exports.nodeType && exports;
      /** Detect free variable `module`. */

      var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
      /** Detect the popular CommonJS extension `module.exports`. */

      var moduleExports = freeModule && freeModule.exports === freeExports;
      /** Built-in value references. */

      var Buffer = moduleExports ? root.Buffer : undefined;
      /* Built-in method references for those with the same name as other `lodash` methods. */

      var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;
      /**
       * Checks if `value` is a buffer.
       *
       * @static
       * @memberOf _
       * @since 4.3.0
       * @category Lang
       * @param {*} value The value to check.
       * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
       * @example
       *
       * _.isBuffer(new Buffer(2));
       * // => true
       *
       * _.isBuffer(new Uint8Array(2));
       * // => false
       */

      var isBuffer = nativeIsBuffer || stubFalse;
      module.exports = isBuffer;
    })(isBuffer$3, isBuffer$3.exports);

    /** Used as references for various `Number` constants. */
    var MAX_SAFE_INTEGER$1 = 9007199254740991;
    /** Used to detect unsigned integer values. */

    var reIsUint = /^(?:0|[1-9]\d*)$/;
    /**
     * Checks if `value` is a valid array-like index.
     *
     * @private
     * @param {*} value The value to check.
     * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
     * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
     */

    function isIndex$1(value, length) {
      var type = typeof value;
      length = length == null ? MAX_SAFE_INTEGER$1 : length;
      return !!length && (type == 'number' || type != 'symbol' && reIsUint.test(value)) && value > -1 && value % 1 == 0 && value < length;
    }

    var _isIndex = isIndex$1;

    /** Used as references for various `Number` constants. */
    var MAX_SAFE_INTEGER = 9007199254740991;
    /**
     * Checks if `value` is a valid array-like length.
     *
     * **Note:** This method is loosely based on
     * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
     * @example
     *
     * _.isLength(3);
     * // => true
     *
     * _.isLength(Number.MIN_VALUE);
     * // => false
     *
     * _.isLength(Infinity);
     * // => false
     *
     * _.isLength('3');
     * // => false
     */

    function isLength$2(value) {
      return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
    }

    var isLength_1 = isLength$2;

    var baseGetTag$1 = _baseGetTag,
        isLength$1 = isLength_1,
        isObjectLike$3 = isObjectLike_1;
    /** `Object#toString` result references. */

    var argsTag$2 = '[object Arguments]',
        arrayTag$2 = '[object Array]',
        boolTag$3 = '[object Boolean]',
        dateTag$3 = '[object Date]',
        errorTag$2 = '[object Error]',
        funcTag$1 = '[object Function]',
        mapTag$5 = '[object Map]',
        numberTag$3 = '[object Number]',
        objectTag$3 = '[object Object]',
        regexpTag$3 = '[object RegExp]',
        setTag$5 = '[object Set]',
        stringTag$3 = '[object String]',
        weakMapTag$2 = '[object WeakMap]';
    var arrayBufferTag$3 = '[object ArrayBuffer]',
        dataViewTag$4 = '[object DataView]',
        float32Tag$2 = '[object Float32Array]',
        float64Tag$2 = '[object Float64Array]',
        int8Tag$2 = '[object Int8Array]',
        int16Tag$2 = '[object Int16Array]',
        int32Tag$2 = '[object Int32Array]',
        uint8Tag$2 = '[object Uint8Array]',
        uint8ClampedTag$2 = '[object Uint8ClampedArray]',
        uint16Tag$2 = '[object Uint16Array]',
        uint32Tag$2 = '[object Uint32Array]';
    /** Used to identify `toStringTag` values of typed arrays. */

    var typedArrayTags = {};
    typedArrayTags[float32Tag$2] = typedArrayTags[float64Tag$2] = typedArrayTags[int8Tag$2] = typedArrayTags[int16Tag$2] = typedArrayTags[int32Tag$2] = typedArrayTags[uint8Tag$2] = typedArrayTags[uint8ClampedTag$2] = typedArrayTags[uint16Tag$2] = typedArrayTags[uint32Tag$2] = true;
    typedArrayTags[argsTag$2] = typedArrayTags[arrayTag$2] = typedArrayTags[arrayBufferTag$3] = typedArrayTags[boolTag$3] = typedArrayTags[dataViewTag$4] = typedArrayTags[dateTag$3] = typedArrayTags[errorTag$2] = typedArrayTags[funcTag$1] = typedArrayTags[mapTag$5] = typedArrayTags[numberTag$3] = typedArrayTags[objectTag$3] = typedArrayTags[regexpTag$3] = typedArrayTags[setTag$5] = typedArrayTags[stringTag$3] = typedArrayTags[weakMapTag$2] = false;
    /**
     * The base implementation of `_.isTypedArray` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
     */

    function baseIsTypedArray$1(value) {
      return isObjectLike$3(value) && isLength$1(value.length) && !!typedArrayTags[baseGetTag$1(value)];
    }

    var _baseIsTypedArray = baseIsTypedArray$1;

    /**
     * The base implementation of `_.unary` without support for storing metadata.
     *
     * @private
     * @param {Function} func The function to cap arguments for.
     * @returns {Function} Returns the new capped function.
     */

    function baseUnary$3(func) {
      return function (value) {
        return func(value);
      };
    }

    var _baseUnary = baseUnary$3;

    var _nodeUtil = {exports: {}};

    (function (module, exports) {
      var freeGlobal = _freeGlobal;
      /** Detect free variable `exports`. */

      var freeExports = exports && !exports.nodeType && exports;
      /** Detect free variable `module`. */

      var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
      /** Detect the popular CommonJS extension `module.exports`. */

      var moduleExports = freeModule && freeModule.exports === freeExports;
      /** Detect free variable `process` from Node.js. */

      var freeProcess = moduleExports && freeGlobal.process;
      /** Used to access faster Node.js helpers. */

      var nodeUtil = function () {
        try {
          // Use `util.types` for Node.js 10+.
          var types = freeModule && freeModule.require && freeModule.require('util').types;

          if (types) {
            return types;
          } // Legacy `process.binding('util')` for Node.js < 10.


          return freeProcess && freeProcess.binding && freeProcess.binding('util');
        } catch (e) {}
      }();

      module.exports = nodeUtil;
    })(_nodeUtil, _nodeUtil.exports);

    var baseIsTypedArray = _baseIsTypedArray,
        baseUnary$2 = _baseUnary,
        nodeUtil$2 = _nodeUtil.exports;
    /* Node.js helper references. */

    var nodeIsTypedArray = nodeUtil$2 && nodeUtil$2.isTypedArray;
    /**
     * Checks if `value` is classified as a typed array.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
     * @example
     *
     * _.isTypedArray(new Uint8Array);
     * // => true
     *
     * _.isTypedArray([]);
     * // => false
     */

    var isTypedArray$2 = nodeIsTypedArray ? baseUnary$2(nodeIsTypedArray) : baseIsTypedArray;
    var isTypedArray_1 = isTypedArray$2;

    var baseTimes = _baseTimes,
        isArguments = isArguments_1,
        isArray$3 = isArray_1,
        isBuffer$2 = isBuffer$3.exports,
        isIndex = _isIndex,
        isTypedArray$1 = isTypedArray_1;
    /** Used for built-in method references. */

    var objectProto$7 = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$5 = objectProto$7.hasOwnProperty;
    /**
     * Creates an array of the enumerable property names of the array-like `value`.
     *
     * @private
     * @param {*} value The value to query.
     * @param {boolean} inherited Specify returning inherited property names.
     * @returns {Array} Returns the array of property names.
     */

    function arrayLikeKeys$2(value, inherited) {
      var isArr = isArray$3(value),
          isArg = !isArr && isArguments(value),
          isBuff = !isArr && !isArg && isBuffer$2(value),
          isType = !isArr && !isArg && !isBuff && isTypedArray$1(value),
          skipIndexes = isArr || isArg || isBuff || isType,
          result = skipIndexes ? baseTimes(value.length, String) : [],
          length = result.length;

      for (var key in value) {
        if ((inherited || hasOwnProperty$5.call(value, key)) && !(skipIndexes && ( // Safari 9 has enumerable `arguments.length` in strict mode.
        key == 'length' || // Node.js 0.10 has enumerable non-index properties on buffers.
        isBuff && (key == 'offset' || key == 'parent') || // PhantomJS 2 has enumerable non-index properties on typed arrays.
        isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset') || // Skip index properties.
        isIndex(key, length)))) {
          result.push(key);
        }
      }

      return result;
    }

    var _arrayLikeKeys = arrayLikeKeys$2;

    /** Used for built-in method references. */
    var objectProto$6 = Object.prototype;
    /**
     * Checks if `value` is likely a prototype object.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
     */

    function isPrototype$3(value) {
      var Ctor = value && value.constructor,
          proto = typeof Ctor == 'function' && Ctor.prototype || objectProto$6;
      return value === proto;
    }

    var _isPrototype = isPrototype$3;

    /**
     * Creates a unary function that invokes `func` with its argument transformed.
     *
     * @private
     * @param {Function} func The function to wrap.
     * @param {Function} transform The argument transform.
     * @returns {Function} Returns the new function.
     */

    function overArg$2(func, transform) {
      return function (arg) {
        return func(transform(arg));
      };
    }

    var _overArg = overArg$2;

    var overArg$1 = _overArg;
    /* Built-in method references for those with the same name as other `lodash` methods. */

    var nativeKeys$1 = overArg$1(Object.keys, Object);
    var _nativeKeys = nativeKeys$1;

    var isPrototype$2 = _isPrototype,
        nativeKeys = _nativeKeys;
    /** Used for built-in method references. */

    var objectProto$5 = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$4 = objectProto$5.hasOwnProperty;
    /**
     * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names.
     */

    function baseKeys$1(object) {
      if (!isPrototype$2(object)) {
        return nativeKeys(object);
      }

      var result = [];

      for (var key in Object(object)) {
        if (hasOwnProperty$4.call(object, key) && key != 'constructor') {
          result.push(key);
        }
      }

      return result;
    }

    var _baseKeys = baseKeys$1;

    var isFunction = isFunction_1,
        isLength = isLength_1;
    /**
     * Checks if `value` is array-like. A value is considered array-like if it's
     * not a function and has a `value.length` that's an integer greater than or
     * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
     * @example
     *
     * _.isArrayLike([1, 2, 3]);
     * // => true
     *
     * _.isArrayLike(document.body.children);
     * // => true
     *
     * _.isArrayLike('abc');
     * // => true
     *
     * _.isArrayLike(_.noop);
     * // => false
     */

    function isArrayLike$2(value) {
      return value != null && isLength(value.length) && !isFunction(value);
    }

    var isArrayLike_1 = isArrayLike$2;

    var arrayLikeKeys$1 = _arrayLikeKeys,
        baseKeys = _baseKeys,
        isArrayLike$1 = isArrayLike_1;
    /**
     * Creates an array of the own enumerable property names of `object`.
     *
     * **Note:** Non-object values are coerced to objects. See the
     * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
     * for more details.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Object
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names.
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.keys(new Foo);
     * // => ['a', 'b'] (iteration order is not guaranteed)
     *
     * _.keys('hi');
     * // => ['0', '1']
     */

    function keys$3(object) {
      return isArrayLike$1(object) ? arrayLikeKeys$1(object) : baseKeys(object);
    }

    var keys_1 = keys$3;

    var copyObject$3 = _copyObject,
        keys$2 = keys_1;
    /**
     * The base implementation of `_.assign` without support for multiple sources
     * or `customizer` functions.
     *
     * @private
     * @param {Object} object The destination object.
     * @param {Object} source The source object.
     * @returns {Object} Returns `object`.
     */

    function baseAssign$1(object, source) {
      return object && copyObject$3(source, keys$2(source), object);
    }

    var _baseAssign = baseAssign$1;

    /**
     * This function is like
     * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
     * except that it includes inherited enumerable properties.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names.
     */

    function nativeKeysIn$1(object) {
      var result = [];

      if (object != null) {
        for (var key in Object(object)) {
          result.push(key);
        }
      }

      return result;
    }

    var _nativeKeysIn = nativeKeysIn$1;

    var isObject$2 = isObject_1,
        isPrototype$1 = _isPrototype,
        nativeKeysIn = _nativeKeysIn;
    /** Used for built-in method references. */

    var objectProto$4 = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$3 = objectProto$4.hasOwnProperty;
    /**
     * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names.
     */

    function baseKeysIn$1(object) {
      if (!isObject$2(object)) {
        return nativeKeysIn(object);
      }

      var isProto = isPrototype$1(object),
          result = [];

      for (var key in object) {
        if (!(key == 'constructor' && (isProto || !hasOwnProperty$3.call(object, key)))) {
          result.push(key);
        }
      }

      return result;
    }

    var _baseKeysIn = baseKeysIn$1;

    var arrayLikeKeys = _arrayLikeKeys,
        baseKeysIn = _baseKeysIn,
        isArrayLike = isArrayLike_1;
    /**
     * Creates an array of the own and inherited enumerable property names of `object`.
     *
     * **Note:** Non-object values are coerced to objects.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Object
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names.
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.keysIn(new Foo);
     * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
     */

    function keysIn$3(object) {
      return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
    }

    var keysIn_1 = keysIn$3;

    var copyObject$2 = _copyObject,
        keysIn$2 = keysIn_1;
    /**
     * The base implementation of `_.assignIn` without support for multiple sources
     * or `customizer` functions.
     *
     * @private
     * @param {Object} object The destination object.
     * @param {Object} source The source object.
     * @returns {Object} Returns `object`.
     */

    function baseAssignIn$1(object, source) {
      return object && copyObject$2(source, keysIn$2(source), object);
    }

    var _baseAssignIn = baseAssignIn$1;

    var _cloneBuffer = {exports: {}};

    (function (module, exports) {
      var root = _root;
      /** Detect free variable `exports`. */

      var freeExports = exports && !exports.nodeType && exports;
      /** Detect free variable `module`. */

      var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
      /** Detect the popular CommonJS extension `module.exports`. */

      var moduleExports = freeModule && freeModule.exports === freeExports;
      /** Built-in value references. */

      var Buffer = moduleExports ? root.Buffer : undefined,
          allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined;
      /**
       * Creates a clone of  `buffer`.
       *
       * @private
       * @param {Buffer} buffer The buffer to clone.
       * @param {boolean} [isDeep] Specify a deep clone.
       * @returns {Buffer} Returns the cloned buffer.
       */

      function cloneBuffer(buffer, isDeep) {
        if (isDeep) {
          return buffer.slice();
        }

        var length = buffer.length,
            result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
        buffer.copy(result);
        return result;
      }

      module.exports = cloneBuffer;
    })(_cloneBuffer, _cloneBuffer.exports);

    /**
     * Copies the values of `source` to `array`.
     *
     * @private
     * @param {Array} source The array to copy values from.
     * @param {Array} [array=[]] The array to copy values to.
     * @returns {Array} Returns `array`.
     */

    function copyArray$1(source, array) {
      var index = -1,
          length = source.length;
      array || (array = Array(length));

      while (++index < length) {
        array[index] = source[index];
      }

      return array;
    }

    var _copyArray = copyArray$1;

    /**
     * A specialized version of `_.filter` for arrays without support for
     * iteratee shorthands.
     *
     * @private
     * @param {Array} [array] The array to iterate over.
     * @param {Function} predicate The function invoked per iteration.
     * @returns {Array} Returns the new filtered array.
     */

    function arrayFilter$1(array, predicate) {
      var index = -1,
          length = array == null ? 0 : array.length,
          resIndex = 0,
          result = [];

      while (++index < length) {
        var value = array[index];

        if (predicate(value, index, array)) {
          result[resIndex++] = value;
        }
      }

      return result;
    }

    var _arrayFilter = arrayFilter$1;

    /**
     * This method returns a new empty array.
     *
     * @static
     * @memberOf _
     * @since 4.13.0
     * @category Util
     * @returns {Array} Returns the new empty array.
     * @example
     *
     * var arrays = _.times(2, _.stubArray);
     *
     * console.log(arrays);
     * // => [[], []]
     *
     * console.log(arrays[0] === arrays[1]);
     * // => false
     */

    function stubArray$2() {
      return [];
    }

    var stubArray_1 = stubArray$2;

    var arrayFilter = _arrayFilter,
        stubArray$1 = stubArray_1;
    /** Used for built-in method references. */

    var objectProto$3 = Object.prototype;
    /** Built-in value references. */

    var propertyIsEnumerable = objectProto$3.propertyIsEnumerable;
    /* Built-in method references for those with the same name as other `lodash` methods. */

    var nativeGetSymbols$1 = Object.getOwnPropertySymbols;
    /**
     * Creates an array of the own enumerable symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of symbols.
     */

    var getSymbols$3 = !nativeGetSymbols$1 ? stubArray$1 : function (object) {
      if (object == null) {
        return [];
      }

      object = Object(object);
      return arrayFilter(nativeGetSymbols$1(object), function (symbol) {
        return propertyIsEnumerable.call(object, symbol);
      });
    };
    var _getSymbols = getSymbols$3;

    var copyObject$1 = _copyObject,
        getSymbols$2 = _getSymbols;
    /**
     * Copies own symbols of `source` to `object`.
     *
     * @private
     * @param {Object} source The object to copy symbols from.
     * @param {Object} [object={}] The object to copy symbols to.
     * @returns {Object} Returns `object`.
     */

    function copySymbols$1(source, object) {
      return copyObject$1(source, getSymbols$2(source), object);
    }

    var _copySymbols = copySymbols$1;

    /**
     * Appends the elements of `values` to `array`.
     *
     * @private
     * @param {Array} array The array to modify.
     * @param {Array} values The values to append.
     * @returns {Array} Returns `array`.
     */

    function arrayPush$2(array, values) {
      var index = -1,
          length = values.length,
          offset = array.length;

      while (++index < length) {
        array[offset + index] = values[index];
      }

      return array;
    }

    var _arrayPush = arrayPush$2;

    var overArg = _overArg;
    /** Built-in value references. */

    var getPrototype$2 = overArg(Object.getPrototypeOf, Object);
    var _getPrototype = getPrototype$2;

    var arrayPush$1 = _arrayPush,
        getPrototype$1 = _getPrototype,
        getSymbols$1 = _getSymbols,
        stubArray = stubArray_1;
    /* Built-in method references for those with the same name as other `lodash` methods. */

    var nativeGetSymbols = Object.getOwnPropertySymbols;
    /**
     * Creates an array of the own and inherited enumerable symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of symbols.
     */

    var getSymbolsIn$2 = !nativeGetSymbols ? stubArray : function (object) {
      var result = [];

      while (object) {
        arrayPush$1(result, getSymbols$1(object));
        object = getPrototype$1(object);
      }

      return result;
    };
    var _getSymbolsIn = getSymbolsIn$2;

    var copyObject = _copyObject,
        getSymbolsIn$1 = _getSymbolsIn;
    /**
     * Copies own and inherited symbols of `source` to `object`.
     *
     * @private
     * @param {Object} source The object to copy symbols from.
     * @param {Object} [object={}] The object to copy symbols to.
     * @returns {Object} Returns `object`.
     */

    function copySymbolsIn$1(source, object) {
      return copyObject(source, getSymbolsIn$1(source), object);
    }

    var _copySymbolsIn = copySymbolsIn$1;

    var arrayPush = _arrayPush,
        isArray$2 = isArray_1;
    /**
     * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
     * `keysFunc` and `symbolsFunc` to get the enumerable property names and
     * symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {Function} keysFunc The function to get the keys of `object`.
     * @param {Function} symbolsFunc The function to get the symbols of `object`.
     * @returns {Array} Returns the array of property names and symbols.
     */

    function baseGetAllKeys$2(object, keysFunc, symbolsFunc) {
      var result = keysFunc(object);
      return isArray$2(object) ? result : arrayPush(result, symbolsFunc(object));
    }

    var _baseGetAllKeys = baseGetAllKeys$2;

    var baseGetAllKeys$1 = _baseGetAllKeys,
        getSymbols = _getSymbols,
        keys$1 = keys_1;
    /**
     * Creates an array of own enumerable property names and symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names and symbols.
     */

    function getAllKeys$2(object) {
      return baseGetAllKeys$1(object, keys$1, getSymbols);
    }

    var _getAllKeys = getAllKeys$2;

    var baseGetAllKeys = _baseGetAllKeys,
        getSymbolsIn = _getSymbolsIn,
        keysIn$1 = keysIn_1;
    /**
     * Creates an array of own and inherited enumerable property names and
     * symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names and symbols.
     */

    function getAllKeysIn$1(object) {
      return baseGetAllKeys(object, keysIn$1, getSymbolsIn);
    }

    var _getAllKeysIn = getAllKeysIn$1;

    var getNative$3 = _getNative,
        root$4 = _root;
    /* Built-in method references that are verified to be native. */

    var DataView$2 = getNative$3(root$4, 'DataView');
    var _DataView = DataView$2;

    var getNative$2 = _getNative,
        root$3 = _root;
    /* Built-in method references that are verified to be native. */

    var Promise$2 = getNative$2(root$3, 'Promise');
    var _Promise = Promise$2;

    var getNative$1 = _getNative,
        root$2 = _root;
    /* Built-in method references that are verified to be native. */

    var Set$2 = getNative$1(root$2, 'Set');
    var _Set = Set$2;

    var getNative = _getNative,
        root$1 = _root;
    /* Built-in method references that are verified to be native. */

    var WeakMap$1 = getNative(root$1, 'WeakMap');
    var _WeakMap = WeakMap$1;

    var DataView$1 = _DataView,
        Map$1 = _Map,
        Promise$1 = _Promise,
        Set$1 = _Set,
        WeakMap = _WeakMap,
        baseGetTag = _baseGetTag,
        toSource = _toSource;
    /** `Object#toString` result references. */

    var mapTag$4 = '[object Map]',
        objectTag$2 = '[object Object]',
        promiseTag = '[object Promise]',
        setTag$4 = '[object Set]',
        weakMapTag$1 = '[object WeakMap]';
    var dataViewTag$3 = '[object DataView]';
    /** Used to detect maps, sets, and weakmaps. */

    var dataViewCtorString = toSource(DataView$1),
        mapCtorString = toSource(Map$1),
        promiseCtorString = toSource(Promise$1),
        setCtorString = toSource(Set$1),
        weakMapCtorString = toSource(WeakMap);
    /**
     * Gets the `toStringTag` of `value`.
     *
     * @private
     * @param {*} value The value to query.
     * @returns {string} Returns the `toStringTag`.
     */

    var getTag$4 = baseGetTag; // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.

    if (DataView$1 && getTag$4(new DataView$1(new ArrayBuffer(1))) != dataViewTag$3 || Map$1 && getTag$4(new Map$1()) != mapTag$4 || Promise$1 && getTag$4(Promise$1.resolve()) != promiseTag || Set$1 && getTag$4(new Set$1()) != setTag$4 || WeakMap && getTag$4(new WeakMap()) != weakMapTag$1) {
      getTag$4 = function (value) {
        var result = baseGetTag(value),
            Ctor = result == objectTag$2 ? value.constructor : undefined,
            ctorString = Ctor ? toSource(Ctor) : '';

        if (ctorString) {
          switch (ctorString) {
            case dataViewCtorString:
              return dataViewTag$3;

            case mapCtorString:
              return mapTag$4;

            case promiseCtorString:
              return promiseTag;

            case setCtorString:
              return setTag$4;

            case weakMapCtorString:
              return weakMapTag$1;
          }
        }

        return result;
      };
    }

    var _getTag = getTag$4;

    /** Used for built-in method references. */
    var objectProto$2 = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$2 = objectProto$2.hasOwnProperty;
    /**
     * Initializes an array clone.
     *
     * @private
     * @param {Array} array The array to clone.
     * @returns {Array} Returns the initialized clone.
     */

    function initCloneArray$1(array) {
      var length = array.length,
          result = new array.constructor(length); // Add properties assigned by `RegExp#exec`.

      if (length && typeof array[0] == 'string' && hasOwnProperty$2.call(array, 'index')) {
        result.index = array.index;
        result.input = array.input;
      }

      return result;
    }

    var _initCloneArray = initCloneArray$1;

    var root = _root;
    /** Built-in value references. */

    var Uint8Array$3 = root.Uint8Array;
    var _Uint8Array = Uint8Array$3;

    var Uint8Array$2 = _Uint8Array;
    /**
     * Creates a clone of `arrayBuffer`.
     *
     * @private
     * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
     * @returns {ArrayBuffer} Returns the cloned array buffer.
     */

    function cloneArrayBuffer$3(arrayBuffer) {
      var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
      new Uint8Array$2(result).set(new Uint8Array$2(arrayBuffer));
      return result;
    }

    var _cloneArrayBuffer = cloneArrayBuffer$3;

    var cloneArrayBuffer$2 = _cloneArrayBuffer;
    /**
     * Creates a clone of `dataView`.
     *
     * @private
     * @param {Object} dataView The data view to clone.
     * @param {boolean} [isDeep] Specify a deep clone.
     * @returns {Object} Returns the cloned data view.
     */

    function cloneDataView$1(dataView, isDeep) {
      var buffer = isDeep ? cloneArrayBuffer$2(dataView.buffer) : dataView.buffer;
      return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
    }

    var _cloneDataView = cloneDataView$1;

    /** Used to match `RegExp` flags from their coerced string values. */
    var reFlags = /\w*$/;
    /**
     * Creates a clone of `regexp`.
     *
     * @private
     * @param {Object} regexp The regexp to clone.
     * @returns {Object} Returns the cloned regexp.
     */

    function cloneRegExp$1(regexp) {
      var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
      result.lastIndex = regexp.lastIndex;
      return result;
    }

    var _cloneRegExp = cloneRegExp$1;

    var Symbol$2 = _Symbol;
    /** Used to convert symbols to primitives and strings. */

    var symbolProto$1 = Symbol$2 ? Symbol$2.prototype : undefined,
        symbolValueOf$1 = symbolProto$1 ? symbolProto$1.valueOf : undefined;
    /**
     * Creates a clone of the `symbol` object.
     *
     * @private
     * @param {Object} symbol The symbol object to clone.
     * @returns {Object} Returns the cloned symbol object.
     */

    function cloneSymbol$1(symbol) {
      return symbolValueOf$1 ? Object(symbolValueOf$1.call(symbol)) : {};
    }

    var _cloneSymbol = cloneSymbol$1;

    var cloneArrayBuffer$1 = _cloneArrayBuffer;
    /**
     * Creates a clone of `typedArray`.
     *
     * @private
     * @param {Object} typedArray The typed array to clone.
     * @param {boolean} [isDeep] Specify a deep clone.
     * @returns {Object} Returns the cloned typed array.
     */

    function cloneTypedArray$1(typedArray, isDeep) {
      var buffer = isDeep ? cloneArrayBuffer$1(typedArray.buffer) : typedArray.buffer;
      return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
    }

    var _cloneTypedArray = cloneTypedArray$1;

    var cloneArrayBuffer = _cloneArrayBuffer,
        cloneDataView = _cloneDataView,
        cloneRegExp = _cloneRegExp,
        cloneSymbol = _cloneSymbol,
        cloneTypedArray = _cloneTypedArray;
    /** `Object#toString` result references. */

    var boolTag$2 = '[object Boolean]',
        dateTag$2 = '[object Date]',
        mapTag$3 = '[object Map]',
        numberTag$2 = '[object Number]',
        regexpTag$2 = '[object RegExp]',
        setTag$3 = '[object Set]',
        stringTag$2 = '[object String]',
        symbolTag$2 = '[object Symbol]';
    var arrayBufferTag$2 = '[object ArrayBuffer]',
        dataViewTag$2 = '[object DataView]',
        float32Tag$1 = '[object Float32Array]',
        float64Tag$1 = '[object Float64Array]',
        int8Tag$1 = '[object Int8Array]',
        int16Tag$1 = '[object Int16Array]',
        int32Tag$1 = '[object Int32Array]',
        uint8Tag$1 = '[object Uint8Array]',
        uint8ClampedTag$1 = '[object Uint8ClampedArray]',
        uint16Tag$1 = '[object Uint16Array]',
        uint32Tag$1 = '[object Uint32Array]';
    /**
     * Initializes an object clone based on its `toStringTag`.
     *
     * **Note:** This function only supports cloning values with tags of
     * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
     *
     * @private
     * @param {Object} object The object to clone.
     * @param {string} tag The `toStringTag` of the object to clone.
     * @param {boolean} [isDeep] Specify a deep clone.
     * @returns {Object} Returns the initialized clone.
     */

    function initCloneByTag$1(object, tag, isDeep) {
      var Ctor = object.constructor;

      switch (tag) {
        case arrayBufferTag$2:
          return cloneArrayBuffer(object);

        case boolTag$2:
        case dateTag$2:
          return new Ctor(+object);

        case dataViewTag$2:
          return cloneDataView(object, isDeep);

        case float32Tag$1:
        case float64Tag$1:
        case int8Tag$1:
        case int16Tag$1:
        case int32Tag$1:
        case uint8Tag$1:
        case uint8ClampedTag$1:
        case uint16Tag$1:
        case uint32Tag$1:
          return cloneTypedArray(object, isDeep);

        case mapTag$3:
          return new Ctor();

        case numberTag$2:
        case stringTag$2:
          return new Ctor(object);

        case regexpTag$2:
          return cloneRegExp(object);

        case setTag$3:
          return new Ctor();

        case symbolTag$2:
          return cloneSymbol(object);
      }
    }

    var _initCloneByTag = initCloneByTag$1;

    var isObject$1 = isObject_1;
    /** Built-in value references. */

    var objectCreate = Object.create;
    /**
     * The base implementation of `_.create` without support for assigning
     * properties to the created object.
     *
     * @private
     * @param {Object} proto The object to inherit from.
     * @returns {Object} Returns the new object.
     */

    var baseCreate$1 = function () {
      function object() {}

      return function (proto) {
        if (!isObject$1(proto)) {
          return {};
        }

        if (objectCreate) {
          return objectCreate(proto);
        }

        object.prototype = proto;
        var result = new object();
        object.prototype = undefined;
        return result;
      };
    }();

    var _baseCreate = baseCreate$1;

    var baseCreate = _baseCreate,
        getPrototype = _getPrototype,
        isPrototype = _isPrototype;
    /**
     * Initializes an object clone.
     *
     * @private
     * @param {Object} object The object to clone.
     * @returns {Object} Returns the initialized clone.
     */

    function initCloneObject$1(object) {
      return typeof object.constructor == 'function' && !isPrototype(object) ? baseCreate(getPrototype(object)) : {};
    }

    var _initCloneObject = initCloneObject$1;

    var getTag$3 = _getTag,
        isObjectLike$2 = isObjectLike_1;
    /** `Object#toString` result references. */

    var mapTag$2 = '[object Map]';
    /**
     * The base implementation of `_.isMap` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
     */

    function baseIsMap$1(value) {
      return isObjectLike$2(value) && getTag$3(value) == mapTag$2;
    }

    var _baseIsMap = baseIsMap$1;

    var baseIsMap = _baseIsMap,
        baseUnary$1 = _baseUnary,
        nodeUtil$1 = _nodeUtil.exports;
    /* Node.js helper references. */

    var nodeIsMap = nodeUtil$1 && nodeUtil$1.isMap;
    /**
     * Checks if `value` is classified as a `Map` object.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
     * @example
     *
     * _.isMap(new Map);
     * // => true
     *
     * _.isMap(new WeakMap);
     * // => false
     */

    var isMap$1 = nodeIsMap ? baseUnary$1(nodeIsMap) : baseIsMap;
    var isMap_1 = isMap$1;

    var getTag$2 = _getTag,
        isObjectLike$1 = isObjectLike_1;
    /** `Object#toString` result references. */

    var setTag$2 = '[object Set]';
    /**
     * The base implementation of `_.isSet` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
     */

    function baseIsSet$1(value) {
      return isObjectLike$1(value) && getTag$2(value) == setTag$2;
    }

    var _baseIsSet = baseIsSet$1;

    var baseIsSet = _baseIsSet,
        baseUnary = _baseUnary,
        nodeUtil = _nodeUtil.exports;
    /* Node.js helper references. */

    var nodeIsSet = nodeUtil && nodeUtil.isSet;
    /**
     * Checks if `value` is classified as a `Set` object.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
     * @example
     *
     * _.isSet(new Set);
     * // => true
     *
     * _.isSet(new WeakSet);
     * // => false
     */

    var isSet$1 = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
    var isSet_1 = isSet$1;

    var Stack$1 = _Stack,
        arrayEach = _arrayEach,
        assignValue = _assignValue,
        baseAssign = _baseAssign,
        baseAssignIn = _baseAssignIn,
        cloneBuffer = _cloneBuffer.exports,
        copyArray = _copyArray,
        copySymbols = _copySymbols,
        copySymbolsIn = _copySymbolsIn,
        getAllKeys$1 = _getAllKeys,
        getAllKeysIn = _getAllKeysIn,
        getTag$1 = _getTag,
        initCloneArray = _initCloneArray,
        initCloneByTag = _initCloneByTag,
        initCloneObject = _initCloneObject,
        isArray$1 = isArray_1,
        isBuffer$1 = isBuffer$3.exports,
        isMap = isMap_1,
        isObject = isObject_1,
        isSet = isSet_1,
        keys = keys_1,
        keysIn = keysIn_1;
    /** Used to compose bitmasks for cloning. */

    var CLONE_DEEP_FLAG$1 = 1,
        CLONE_FLAT_FLAG = 2,
        CLONE_SYMBOLS_FLAG$1 = 4;
    /** `Object#toString` result references. */

    var argsTag$1 = '[object Arguments]',
        arrayTag$1 = '[object Array]',
        boolTag$1 = '[object Boolean]',
        dateTag$1 = '[object Date]',
        errorTag$1 = '[object Error]',
        funcTag = '[object Function]',
        genTag = '[object GeneratorFunction]',
        mapTag$1 = '[object Map]',
        numberTag$1 = '[object Number]',
        objectTag$1 = '[object Object]',
        regexpTag$1 = '[object RegExp]',
        setTag$1 = '[object Set]',
        stringTag$1 = '[object String]',
        symbolTag$1 = '[object Symbol]',
        weakMapTag = '[object WeakMap]';
    var arrayBufferTag$1 = '[object ArrayBuffer]',
        dataViewTag$1 = '[object DataView]',
        float32Tag = '[object Float32Array]',
        float64Tag = '[object Float64Array]',
        int8Tag = '[object Int8Array]',
        int16Tag = '[object Int16Array]',
        int32Tag = '[object Int32Array]',
        uint8Tag = '[object Uint8Array]',
        uint8ClampedTag = '[object Uint8ClampedArray]',
        uint16Tag = '[object Uint16Array]',
        uint32Tag = '[object Uint32Array]';
    /** Used to identify `toStringTag` values supported by `_.clone`. */

    var cloneableTags = {};
    cloneableTags[argsTag$1] = cloneableTags[arrayTag$1] = cloneableTags[arrayBufferTag$1] = cloneableTags[dataViewTag$1] = cloneableTags[boolTag$1] = cloneableTags[dateTag$1] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[mapTag$1] = cloneableTags[numberTag$1] = cloneableTags[objectTag$1] = cloneableTags[regexpTag$1] = cloneableTags[setTag$1] = cloneableTags[stringTag$1] = cloneableTags[symbolTag$1] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
    cloneableTags[errorTag$1] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false;
    /**
     * The base implementation of `_.clone` and `_.cloneDeep` which tracks
     * traversed objects.
     *
     * @private
     * @param {*} value The value to clone.
     * @param {boolean} bitmask The bitmask flags.
     *  1 - Deep clone
     *  2 - Flatten inherited properties
     *  4 - Clone symbols
     * @param {Function} [customizer] The function to customize cloning.
     * @param {string} [key] The key of `value`.
     * @param {Object} [object] The parent object of `value`.
     * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
     * @returns {*} Returns the cloned value.
     */

    function baseClone$1(value, bitmask, customizer, key, object, stack) {
      var result,
          isDeep = bitmask & CLONE_DEEP_FLAG$1,
          isFlat = bitmask & CLONE_FLAT_FLAG,
          isFull = bitmask & CLONE_SYMBOLS_FLAG$1;

      if (customizer) {
        result = object ? customizer(value, key, object, stack) : customizer(value);
      }

      if (result !== undefined) {
        return result;
      }

      if (!isObject(value)) {
        return value;
      }

      var isArr = isArray$1(value);

      if (isArr) {
        result = initCloneArray(value);

        if (!isDeep) {
          return copyArray(value, result);
        }
      } else {
        var tag = getTag$1(value),
            isFunc = tag == funcTag || tag == genTag;

        if (isBuffer$1(value)) {
          return cloneBuffer(value, isDeep);
        }

        if (tag == objectTag$1 || tag == argsTag$1 || isFunc && !object) {
          result = isFlat || isFunc ? {} : initCloneObject(value);

          if (!isDeep) {
            return isFlat ? copySymbolsIn(value, baseAssignIn(result, value)) : copySymbols(value, baseAssign(result, value));
          }
        } else {
          if (!cloneableTags[tag]) {
            return object ? value : {};
          }

          result = initCloneByTag(value, tag, isDeep);
        }
      } // Check for circular references and return its corresponding clone.


      stack || (stack = new Stack$1());
      var stacked = stack.get(value);

      if (stacked) {
        return stacked;
      }

      stack.set(value, result);

      if (isSet(value)) {
        value.forEach(function (subValue) {
          result.add(baseClone$1(subValue, bitmask, customizer, subValue, value, stack));
        });
      } else if (isMap(value)) {
        value.forEach(function (subValue, key) {
          result.set(key, baseClone$1(subValue, bitmask, customizer, key, value, stack));
        });
      }

      var keysFunc = isFull ? isFlat ? getAllKeysIn : getAllKeys$1 : isFlat ? keysIn : keys;
      var props = isArr ? undefined : keysFunc(value);
      arrayEach(props || value, function (subValue, key) {
        if (props) {
          key = subValue;
          subValue = value[key];
        } // Recursively populate clone (susceptible to call stack limits).


        assignValue(result, key, baseClone$1(subValue, bitmask, customizer, key, value, stack));
      });
      return result;
    }

    var _baseClone = baseClone$1;

    var baseClone = _baseClone;
    /** Used to compose bitmasks for cloning. */

    var CLONE_DEEP_FLAG = 1,
        CLONE_SYMBOLS_FLAG = 4;
    /**
     * This method is like `_.clone` except that it recursively clones `value`.
     *
     * @static
     * @memberOf _
     * @since 1.0.0
     * @category Lang
     * @param {*} value The value to recursively clone.
     * @returns {*} Returns the deep cloned value.
     * @see _.clone
     * @example
     *
     * var objects = [{ 'a': 1 }, { 'b': 2 }];
     *
     * var deep = _.cloneDeep(objects);
     * console.log(deep[0] === objects[0]);
     * // => false
     */

    function cloneDeep(value) {
      return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
    }

    var cloneDeep_1 = cloneDeep;
    var lodashCloneDeep = cloneDeep_1;

    /** Used to stand-in for `undefined` hash values. */
    var HASH_UNDEFINED = '__lodash_hash_undefined__';
    /**
     * Adds `value` to the array cache.
     *
     * @private
     * @name add
     * @memberOf SetCache
     * @alias push
     * @param {*} value The value to cache.
     * @returns {Object} Returns the cache instance.
     */

    function setCacheAdd$1(value) {
      this.__data__.set(value, HASH_UNDEFINED);

      return this;
    }

    var _setCacheAdd = setCacheAdd$1;

    /**
     * Checks if `value` is in the array cache.
     *
     * @private
     * @name has
     * @memberOf SetCache
     * @param {*} value The value to search for.
     * @returns {number} Returns `true` if `value` is found, else `false`.
     */

    function setCacheHas$1(value) {
      return this.__data__.has(value);
    }

    var _setCacheHas = setCacheHas$1;

    var MapCache = _MapCache,
        setCacheAdd = _setCacheAdd,
        setCacheHas = _setCacheHas;
    /**
     *
     * Creates an array cache object to store unique values.
     *
     * @private
     * @constructor
     * @param {Array} [values] The values to cache.
     */

    function SetCache$1(values) {
      var index = -1,
          length = values == null ? 0 : values.length;
      this.__data__ = new MapCache();

      while (++index < length) {
        this.add(values[index]);
      }
    } // Add methods to `SetCache`.


    SetCache$1.prototype.add = SetCache$1.prototype.push = setCacheAdd;
    SetCache$1.prototype.has = setCacheHas;
    var _SetCache = SetCache$1;

    /**
     * A specialized version of `_.some` for arrays without support for iteratee
     * shorthands.
     *
     * @private
     * @param {Array} [array] The array to iterate over.
     * @param {Function} predicate The function invoked per iteration.
     * @returns {boolean} Returns `true` if any element passes the predicate check,
     *  else `false`.
     */

    function arraySome$1(array, predicate) {
      var index = -1,
          length = array == null ? 0 : array.length;

      while (++index < length) {
        if (predicate(array[index], index, array)) {
          return true;
        }
      }

      return false;
    }

    var _arraySome = arraySome$1;

    /**
     * Checks if a `cache` value for `key` exists.
     *
     * @private
     * @param {Object} cache The cache to query.
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */

    function cacheHas$1(cache, key) {
      return cache.has(key);
    }

    var _cacheHas = cacheHas$1;

    var SetCache = _SetCache,
        arraySome = _arraySome,
        cacheHas = _cacheHas;
    /** Used to compose bitmasks for value comparisons. */

    var COMPARE_PARTIAL_FLAG$3 = 1,
        COMPARE_UNORDERED_FLAG$1 = 2;
    /**
     * A specialized version of `baseIsEqualDeep` for arrays with support for
     * partial deep comparisons.
     *
     * @private
     * @param {Array} array The array to compare.
     * @param {Array} other The other array to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} stack Tracks traversed `array` and `other` objects.
     * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
     */

    function equalArrays$2(array, other, bitmask, customizer, equalFunc, stack) {
      var isPartial = bitmask & COMPARE_PARTIAL_FLAG$3,
          arrLength = array.length,
          othLength = other.length;

      if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
        return false;
      } // Check that cyclic values are equal.


      var arrStacked = stack.get(array);
      var othStacked = stack.get(other);

      if (arrStacked && othStacked) {
        return arrStacked == other && othStacked == array;
      }

      var index = -1,
          result = true,
          seen = bitmask & COMPARE_UNORDERED_FLAG$1 ? new SetCache() : undefined;
      stack.set(array, other);
      stack.set(other, array); // Ignore non-index properties.

      while (++index < arrLength) {
        var arrValue = array[index],
            othValue = other[index];

        if (customizer) {
          var compared = isPartial ? customizer(othValue, arrValue, index, other, array, stack) : customizer(arrValue, othValue, index, array, other, stack);
        }

        if (compared !== undefined) {
          if (compared) {
            continue;
          }

          result = false;
          break;
        } // Recursively compare arrays (susceptible to call stack limits).


        if (seen) {
          if (!arraySome(other, function (othValue, othIndex) {
            if (!cacheHas(seen, othIndex) && (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
              return seen.push(othIndex);
            }
          })) {
            result = false;
            break;
          }
        } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
          result = false;
          break;
        }
      }

      stack['delete'](array);
      stack['delete'](other);
      return result;
    }

    var _equalArrays = equalArrays$2;

    /**
     * Converts `map` to its key-value pairs.
     *
     * @private
     * @param {Object} map The map to convert.
     * @returns {Array} Returns the key-value pairs.
     */

    function mapToArray$1(map) {
      var index = -1,
          result = Array(map.size);
      map.forEach(function (value, key) {
        result[++index] = [key, value];
      });
      return result;
    }

    var _mapToArray = mapToArray$1;

    /**
     * Converts `set` to an array of its values.
     *
     * @private
     * @param {Object} set The set to convert.
     * @returns {Array} Returns the values.
     */

    function setToArray$1(set) {
      var index = -1,
          result = Array(set.size);
      set.forEach(function (value) {
        result[++index] = value;
      });
      return result;
    }

    var _setToArray = setToArray$1;

    var Symbol$1 = _Symbol,
        Uint8Array$1 = _Uint8Array,
        eq = eq_1,
        equalArrays$1 = _equalArrays,
        mapToArray = _mapToArray,
        setToArray = _setToArray;
    /** Used to compose bitmasks for value comparisons. */

    var COMPARE_PARTIAL_FLAG$2 = 1,
        COMPARE_UNORDERED_FLAG = 2;
    /** `Object#toString` result references. */

    var boolTag = '[object Boolean]',
        dateTag = '[object Date]',
        errorTag = '[object Error]',
        mapTag = '[object Map]',
        numberTag = '[object Number]',
        regexpTag = '[object RegExp]',
        setTag = '[object Set]',
        stringTag = '[object String]',
        symbolTag = '[object Symbol]';
    var arrayBufferTag = '[object ArrayBuffer]',
        dataViewTag = '[object DataView]';
    /** Used to convert symbols to primitives and strings. */

    var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined,
        symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;
    /**
     * A specialized version of `baseIsEqualDeep` for comparing objects of
     * the same `toStringTag`.
     *
     * **Note:** This function only supports comparing values with tags of
     * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
     *
     * @private
     * @param {Object} object The object to compare.
     * @param {Object} other The other object to compare.
     * @param {string} tag The `toStringTag` of the objects to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} stack Tracks traversed `object` and `other` objects.
     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
     */

    function equalByTag$1(object, other, tag, bitmask, customizer, equalFunc, stack) {
      switch (tag) {
        case dataViewTag:
          if (object.byteLength != other.byteLength || object.byteOffset != other.byteOffset) {
            return false;
          }

          object = object.buffer;
          other = other.buffer;

        case arrayBufferTag:
          if (object.byteLength != other.byteLength || !equalFunc(new Uint8Array$1(object), new Uint8Array$1(other))) {
            return false;
          }

          return true;

        case boolTag:
        case dateTag:
        case numberTag:
          // Coerce booleans to `1` or `0` and dates to milliseconds.
          // Invalid dates are coerced to `NaN`.
          return eq(+object, +other);

        case errorTag:
          return object.name == other.name && object.message == other.message;

        case regexpTag:
        case stringTag:
          // Coerce regexes to strings and treat strings, primitives and objects,
          // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
          // for more details.
          return object == other + '';

        case mapTag:
          var convert = mapToArray;

        case setTag:
          var isPartial = bitmask & COMPARE_PARTIAL_FLAG$2;
          convert || (convert = setToArray);

          if (object.size != other.size && !isPartial) {
            return false;
          } // Assume cyclic values are equal.


          var stacked = stack.get(object);

          if (stacked) {
            return stacked == other;
          }

          bitmask |= COMPARE_UNORDERED_FLAG; // Recursively compare objects (susceptible to call stack limits).

          stack.set(object, other);
          var result = equalArrays$1(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
          stack['delete'](object);
          return result;

        case symbolTag:
          if (symbolValueOf) {
            return symbolValueOf.call(object) == symbolValueOf.call(other);
          }

      }

      return false;
    }

    var _equalByTag = equalByTag$1;

    var getAllKeys = _getAllKeys;
    /** Used to compose bitmasks for value comparisons. */

    var COMPARE_PARTIAL_FLAG$1 = 1;
    /** Used for built-in method references. */

    var objectProto$1 = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty$1 = objectProto$1.hasOwnProperty;
    /**
     * A specialized version of `baseIsEqualDeep` for objects with support for
     * partial deep comparisons.
     *
     * @private
     * @param {Object} object The object to compare.
     * @param {Object} other The other object to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} stack Tracks traversed `object` and `other` objects.
     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
     */

    function equalObjects$1(object, other, bitmask, customizer, equalFunc, stack) {
      var isPartial = bitmask & COMPARE_PARTIAL_FLAG$1,
          objProps = getAllKeys(object),
          objLength = objProps.length,
          othProps = getAllKeys(other),
          othLength = othProps.length;

      if (objLength != othLength && !isPartial) {
        return false;
      }

      var index = objLength;

      while (index--) {
        var key = objProps[index];

        if (!(isPartial ? key in other : hasOwnProperty$1.call(other, key))) {
          return false;
        }
      } // Check that cyclic values are equal.


      var objStacked = stack.get(object);
      var othStacked = stack.get(other);

      if (objStacked && othStacked) {
        return objStacked == other && othStacked == object;
      }

      var result = true;
      stack.set(object, other);
      stack.set(other, object);
      var skipCtor = isPartial;

      while (++index < objLength) {
        key = objProps[index];
        var objValue = object[key],
            othValue = other[key];

        if (customizer) {
          var compared = isPartial ? customizer(othValue, objValue, key, other, object, stack) : customizer(objValue, othValue, key, object, other, stack);
        } // Recursively compare objects (susceptible to call stack limits).


        if (!(compared === undefined ? objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack) : compared)) {
          result = false;
          break;
        }

        skipCtor || (skipCtor = key == 'constructor');
      }

      if (result && !skipCtor) {
        var objCtor = object.constructor,
            othCtor = other.constructor; // Non `Object` object instances with different constructors are not equal.

        if (objCtor != othCtor && 'constructor' in object && 'constructor' in other && !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) {
          result = false;
        }
      }

      stack['delete'](object);
      stack['delete'](other);
      return result;
    }

    var _equalObjects = equalObjects$1;

    var Stack = _Stack,
        equalArrays = _equalArrays,
        equalByTag = _equalByTag,
        equalObjects = _equalObjects,
        getTag = _getTag,
        isArray = isArray_1,
        isBuffer = isBuffer$3.exports,
        isTypedArray = isTypedArray_1;
    /** Used to compose bitmasks for value comparisons. */

    var COMPARE_PARTIAL_FLAG = 1;
    /** `Object#toString` result references. */

    var argsTag = '[object Arguments]',
        arrayTag = '[object Array]',
        objectTag = '[object Object]';
    /** Used for built-in method references. */

    var objectProto = Object.prototype;
    /** Used to check objects for own properties. */

    var hasOwnProperty = objectProto.hasOwnProperty;
    /**
     * A specialized version of `baseIsEqual` for arrays and objects which performs
     * deep comparisons and tracks traversed objects enabling objects with circular
     * references to be compared.
     *
     * @private
     * @param {Object} object The object to compare.
     * @param {Object} other The other object to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} [stack] Tracks traversed `object` and `other` objects.
     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
     */

    function baseIsEqualDeep$1(object, other, bitmask, customizer, equalFunc, stack) {
      var objIsArr = isArray(object),
          othIsArr = isArray(other),
          objTag = objIsArr ? arrayTag : getTag(object),
          othTag = othIsArr ? arrayTag : getTag(other);
      objTag = objTag == argsTag ? objectTag : objTag;
      othTag = othTag == argsTag ? objectTag : othTag;
      var objIsObj = objTag == objectTag,
          othIsObj = othTag == objectTag,
          isSameTag = objTag == othTag;

      if (isSameTag && isBuffer(object)) {
        if (!isBuffer(other)) {
          return false;
        }

        objIsArr = true;
        objIsObj = false;
      }

      if (isSameTag && !objIsObj) {
        stack || (stack = new Stack());
        return objIsArr || isTypedArray(object) ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
      }

      if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
        var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
            othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');

        if (objIsWrapped || othIsWrapped) {
          var objUnwrapped = objIsWrapped ? object.value() : object,
              othUnwrapped = othIsWrapped ? other.value() : other;
          stack || (stack = new Stack());
          return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
        }
      }

      if (!isSameTag) {
        return false;
      }

      stack || (stack = new Stack());
      return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
    }

    var _baseIsEqualDeep = baseIsEqualDeep$1;

    var baseIsEqualDeep = _baseIsEqualDeep,
        isObjectLike = isObjectLike_1;
    /**
     * The base implementation of `_.isEqual` which supports partial comparisons
     * and tracks traversed objects.
     *
     * @private
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @param {boolean} bitmask The bitmask flags.
     *  1 - Unordered comparison
     *  2 - Partial comparison
     * @param {Function} [customizer] The function to customize comparisons.
     * @param {Object} [stack] Tracks traversed `value` and `other` objects.
     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
     */

    function baseIsEqual$1(value, other, bitmask, customizer, stack) {
      if (value === other) {
        return true;
      }

      if (value == null || other == null || !isObjectLike(value) && !isObjectLike(other)) {
        return value !== value && other !== other;
      }

      return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual$1, stack);
    }

    var _baseIsEqual = baseIsEqual$1;

    var baseIsEqual = _baseIsEqual;
    /**
     * Performs a deep comparison between two values to determine if they are
     * equivalent.
     *
     * **Note:** This method supports comparing arrays, array buffers, booleans,
     * date objects, error objects, maps, numbers, `Object` objects, regexes,
     * sets, strings, symbols, and typed arrays. `Object` objects are compared
     * by their own, not inherited, enumerable properties. Functions and DOM
     * nodes are compared by strict equality, i.e. `===`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
     * @example
     *
     * var object = { 'a': 1 };
     * var other = { 'a': 1 };
     *
     * _.isEqual(object, other);
     * // => true
     *
     * object === other;
     * // => false
     */

    function isEqual(value, other) {
      return baseIsEqual(value, other);
    }

    var isEqual_1 = isEqual;
    var lodashIsEqual = isEqual_1;

    function isEditedHSQC(experiment) {
      // detection whether experiment is an edited HSQC
      return experiment.info.pulseSequence.includes('hsqced');
    }

    /**
     * Get all different 2D signals from experiments with allowed signal kinds in "signalKindsToInclude".
     *
     * @param {ExperimentsType} experiments1D
     */

    function getSignals2D(experiments2D) {
      // store valid signals from 2D experiments
      const _signals2D = {};
      Object.keys(experiments2D).forEach(experimentType => {
        const _signals = []; // for now we use the first occurring spectrum only, for each experiment type (current loop) and nuclei combination

        const indices = [];
        const nuclei = [];
        experiments2D[experimentType].forEach((_experiment, i) => {
          const experiment = _experiment;

          if (!nuclei.some(_nuclei => lodashIsEqual(_nuclei, experiment.info.nucleus))) {
            nuclei.push(experiment.info.nucleus);
            indices.push(i);
          }
        });
        indices.forEach(index => {
          const spectrum2D = experiments2D[experimentType][index];
          const atomType = spectrum2D.info.nucleus.map(nucleus => getAtomTypeFromNucleus(nucleus));

          const __signals = spectrum2D.zones.values.map(zone => zone.signals.filter(signal => signal.kind && allowedSignalKinds.includes(signal.kind))).flat();

          __signals.forEach(signal => {
            if (!_signals.some(_signal => checkMatch(_signal.signal.x.delta, signal.x.delta, 0.0) && checkMatch(_signal.signal.y.delta, signal.y.delta, 0.0))) {
              _signals.push({
                experimentType,
                experimentID: spectrum2D.id,
                atomType,
                // @TODO here we assume that only one peak exists for the signal and its intensity indicates the sign
                signal: { ...lodashCloneDeep(signal),
                  sign: isEditedHSQC(spectrum2D) && signal.peaks ? signal.peaks[0].z >= 0 ? 1 : -1 : 0
                }
              });
            }
          });
        });
        _signals2D[experimentType] = _signals;
      });
      return _signals2D;
    }

    /**
     * Get all DEPT signals from experiments with allowed signal kinds in "signalKindsToInclude".
     *
     * @param {ExperimentsType} experiments1DExtra
     */

    function getSignalsDEPT(experiments1DExtra) {
      // store valid signals from 1D extra experiments, e.g. DEPT, APT
      const _signalsDEPT = {}; // store valid signals from 2D experiments

      Object.keys(experiments1DExtra).filter(experimentType => experimentType === 'dept').forEach(experimentType => experiments1DExtra[experimentType].forEach(_experimentDEPT => {
        const experimentDEPT = _experimentDEPT;
        const _signals = [];
        const match = experimentDEPT.info.pulseSequence.match(/\d/g);

        if (match) {
          const mode = match.reduce((_mode, digit) => _mode + digit);
          const atomType = getAtomTypeFromNucleus(experimentDEPT.info.nucleus);

          const __signals = experimentDEPT.ranges.values.map(range => range.signals.filter(signal => signal.kind && allowedSignalKinds.includes(signal.kind)).map(signal => {
            return { ...signal,
              sign: range.absolute > 0 ? 1 : -1
            };
          })).flat();

          __signals.forEach(signal => {
            if (!_signals.some(_signal => checkMatch(_signal.signal.delta, signal.delta, 0.0))) {
              _signals.push({
                experimentType,
                experimentID: experimentDEPT.id,
                mode,
                atomType,
                signal: lodashCloneDeep(signal)
              });
            }
          });

          _signalsDEPT[mode] = _signals;
        }
      }));
      return _signalsDEPT;
    }

    // build an array of experiments, because one could have more than
    // one spectrum in spectra list for one atom type or experiment type

    /**
     * Get all signals from experiments with allowed signal kinds in "signalKindsToInclude".
     *
     * @param {Spectra} spectraData
     */

    function getSignals(spectraData) {
      const experiments = getExperiments(spectraData);
      const experiments1D = getExperiments1D(experiments);
      const experiments1DExtra = getExperiments1DExtra(experiments);
      const experiments2D = getExperiments2D(experiments);
      const signals1D = getSignals1D(experiments1D);
      const signals2D = getSignals2D(experiments2D);
      const signalsDEPT = getSignalsDEPT(experiments1DExtra);
      return {
        signals1D,
        signals2D,
        signalsDEPT
      };
    }

    const BASE62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    const LENGTH = 8;
    function generateID() {
      let id = '';

      for (let i = 0; i < LENGTH; i++) {
        id += BASE62.charAt(Math.floor(Math.random() * 62));
      }

      return id;
    }

    /**
     * Builds a link object with some existing default values.
     *
     * @param {LinkOptions} options
     */

    function buildLink(options) {
      return {
        id: options.id || generateID(),
        experimentType: options.experimentType,
        experimentID: options.experimentID,
        atomType: options.atomType,
        signal: options.signal,
        axis: options.axis,
        match: options.match || [],
        experimentLabel: options.experimentLabel || '',
        pseudo: options.pseudo || false,
        edited: options.edited || {}
      };
    }

    function findLinkedCorrelationsBySignalID(correlations, signalID) {
      return correlations.filter(_correlation => _correlation.link.some(_link => _link.signal.id === signalID));
    }

    /**
     * Checks whether a correlation contains a link by id search.
     *
     * @param {Correlation} correlation
     * @param {Link} link
     */

    function containsLink(correlation, link) {
      return correlation.link.some(_link => _link.experimentType === link.experimentType && _link.experimentID === link.experimentID && lodashIsEqual(_link.atomType, link.atomType) && _link.signal.id === link.signal.id && _link.axis === link.axis);
    }

    /**
     * Checks whether a correlation has links.
     *
     * @param {Correlation} correlation
     */
    function hasLinks(correlation) {
      return correlation.link.length > 0;
    }

    function addSignal(matchedCorrelationIndices, atomType, link, correlations) {
      if (matchedCorrelationIndices.length === 0) {
        // in case of no signal match -> add new signal from 2D
        const newCorrelation = buildCorrelation({
          atomType
        });
        addLink(newCorrelation, link);
        const pseudoIndex = correlations.findIndex(correlation => correlation.atomType === atomType && correlation.pseudo && !hasLinks(correlation));

        if (pseudoIndex >= 0) {
          correlations[pseudoIndex] = newCorrelation;
        } else {
          correlations.push(newCorrelation);
        }
      } else if (!containsLink(correlations[matchedCorrelationIndices[0]], link)) {
        // if allowed then add links from 2D data in first match only
        addLink(correlations[matchedCorrelationIndices[0]], link);
      }
    }

    /**
     * Adds new correlations from 1D and 2D data or adds links to already existing ones.
     *
     * @param {Values} correlations
     * * @param {Experiment1DSignals} signals1D
     * @param {Experiment2DSignals} signals2D
     * @param {Tolerance} tolerance
     */

    function addFromData(correlations, signals1D, signals2D, tolerance) {
      // remove non-pseudo correlation objects without links
      correlations = correlations.filter(correlation => correlation.link.length > 0 || correlation.pseudo); // add from 1D data

      Object.keys(signals1D).forEach(atomType => {
        signals1D[atomType].forEach(signal1D => {
          const linkedCorrelations = findLinkedCorrelationsBySignalID(correlations, signal1D.signal.id || '');

          if (linkedCorrelations.length === 0) {
            const matchedCorrelationIndices = correlations.map((correlation, k) => {
              const correlationDelta = getCorrelationDelta(correlation);
              return !correlation.pseudo && correlation.atomType === atomType && correlationDelta !== undefined && checkMatch(correlationDelta, signal1D.signal.delta, tolerance[atomType]) ? k : -1;
            }).filter(index => index >= 0).filter((index, i, a) => a.indexOf(index) === i);
            const link = buildLink({
              experimentType: signal1D.experimentType,
              experimentID: signal1D.experimentID,
              signal: signal1D.signal,
              atomType: [atomType]
            });
            addSignal(matchedCorrelationIndices, atomType, link, correlations);
          }
        });
      }); // add from 2D
      // add potential new correlations and push new links via shift matches between 1D vs. 2D and 2D vs. 2D

      Object.keys(signals2D).forEach(experimentType => signals2D[experimentType].forEach(signal2D => {
        const linkedCorrelations = findLinkedCorrelationsBySignalID(correlations, signal2D.signal.id || '');

        if (linkedCorrelations.length === 0) {
          signal2D.atomType.forEach((atomType, dim) => {
            const axis = dim === 0 ? 'x' : 'y';
            const matchedCorrelationIndices = correlations.map((correlation, k) => {
              const correlationDelta = getCorrelationDelta(correlation);
              return !correlation.pseudo && correlation.atomType === atomType && correlationDelta !== undefined && checkMatch(correlationDelta, signal2D.signal[axis].delta, tolerance[atomType]) ? k : -1;
            }).filter(index => index >= 0).filter((index, i, a) => a.indexOf(index) === i);
            const link = buildLink({
              experimentType: signal2D.experimentType,
              experimentID: signal2D.experimentID,
              signal: signal2D.signal,
              axis,
              atomType: signal2D.atomType
            });
            addSignal(matchedCorrelationIndices, atomType, link, correlations);
          });
        }
      }));
      return correlations;
    }

    /**
     * Builds a correlation object with some existing default values.
     *
     * @param {CorrelationOptions} options
     */

    function buildCorrelation(options) {
      return {
        id: options.id || generateID(),
        atomType: options.atomType,
        label: options.label || {},
        link: options.link || [],
        equivalence: options.equivalence || 1,
        attachment: options.attachment || {},
        protonsCount: options.protonsCount || [],
        hybridization: options.hybridization || [],
        pseudo: options.pseudo || false,
        edited: options.edited || {}
      };
    }

    function addPseudoCorrelations(correlations, atoms) {
      for (const atomType in atoms) {
        const atomTypeCount = getCorrelationsByAtomType(correlations, atomType).reduce((sum, correlation) => sum + correlation.equivalence, 0); // add missing pseudo correlations

        for (let i = atomTypeCount; i < atoms[atomType]; i++) {
          correlations.push(buildCorrelation({
            atomType,
            pseudo: true
          }));
        }
      }

      return correlations;
    }

    /**
     * Removes a link by id search.
     *
     * @param {Correlation} correlation
     * @param {string} id
     */
    function removeLink(correlation, id) {
      correlation.link = correlation.link.filter(_link => _link.id !== id);
      return correlation;
    }

    /**
     * Removes a match index from a link.
     *
     * @param {Link} link
     * @param {number} index
     */
    function removeMatch(link, index) {
      const indexOf = link.match.indexOf(index);

      if (indexOf >= 0) {
        link.match.splice(indexOf, 1);
      }

      return link;
    }

    function checkPseudoCorrelations(correlations, atoms) {
      for (const atomType in atoms) {
        // consider also pseudo correlations
        const correlationsAtomType = getCorrelationsByAtomType(correlations, atomType);

        if (correlationsAtomType.length > atoms[atomType]) {
          // remove pseudo correlations which are out of limit and not linked
          const pseudoCorrelationsAtomType = correlationsAtomType.filter(correlation => correlation.pseudo && correlation.equivalence === 1 && !hasLinks(correlation));

          for (let i = correlationsAtomType.length - 1; i >= atoms[atomType]; i--) {
            if (pseudoCorrelationsAtomType.length === 0) {
              break;
            }

            const pseudoCorrelationToRemove = pseudoCorrelationsAtomType.pop();

            if (pseudoCorrelationToRemove) {
              correlations.splice(correlations.indexOf(pseudoCorrelationToRemove), 1);
            }
          }
        }
      } // check for deleted links and correct proton counts if no HSQC link exists


      for (const pseudoCorrelation of correlations) {
        if (!pseudoCorrelation.pseudo || pseudoCorrelation.equivalence > 1 || hasLinks(pseudoCorrelation)) {
          continue;
        } // remove wrong (old) match indices and empty links


        const linksToRemove = [];
        const pseudoCorrelationIndex = getCorrelationIndex(correlations, pseudoCorrelation);

        for (const pseudoLink of pseudoCorrelation.link) {
          for (const matchIndex of pseudoLink.match) {
            if (!correlations[matchIndex] || !correlations[matchIndex].link.some(_link => _link.match.includes(pseudoCorrelationIndex))) {
              removeMatch(pseudoLink, matchIndex);
            }
          }

          if (pseudoLink.match.length === 0) {
            linksToRemove.push(pseudoLink);
          }
        }

        for (const pseudoLink of linksToRemove) {
          removeLink(pseudoCorrelation, pseudoLink.id);
        } // correct protons count if no HSQC link was found anymore and the field was not edited manually


        if (!pseudoCorrelation.edited.protonsCount && !pseudoCorrelation.link.some(pseudoLink => pseudoLink.experimentType === 'hsqc')) {
          pseudoCorrelation.protonsCount = [];
        }
      } // filter out correlations with unknown atom types from previous molecular formula


      return Object.keys(atoms).length > 0 ? correlations.filter(correlation => Object.keys(atoms).includes(correlation.atomType)) : correlations;
    }

    function replacePseudoCorrelationsByEquivalences(correlations, atoms) {
      for (const atomType in atoms) {
        // remove pseudo correlations to be replaced by equivalences, starting at the end
        const correlationsAtomType = getCorrelationsByAtomType(correlations, atomType);
        const validCorrelationsAtomType = correlationsAtomType.filter(correlation => !correlation.pseudo || correlation.equivalence > 1 || hasLinks(correlation));
        const atomTypeEquivalencesCount = validCorrelationsAtomType.reduce((sum, correlation) => sum + (correlation.equivalence - 1), 0);
        const pseudoCorrelationsAtomType = correlationsAtomType.filter(correlation => correlation.pseudo && !validCorrelationsAtomType.some(validCorrelation => validCorrelation.id === correlation.id));

        for (let i = 0; i < correlationsAtomType.length - (atoms[atomType] - atomTypeEquivalencesCount); i++) {
          if (pseudoCorrelationsAtomType.length === 0) {
            break;
          }

          const pseudoCorrelationToRemove = pseudoCorrelationsAtomType.pop();

          if (pseudoCorrelationToRemove) {
            correlations.splice(correlations.indexOf(pseudoCorrelationToRemove), 1);
          }
        }
      }

      return correlations;
    }

    /**
     * Adds pseudo correlations if needed, checks for replacement
     * by equivalent atoms and cleanup.
     * @param {Values} correlations
     * @param {string} mf
     */

    function updatePseudoCorrelations(correlations, mf) {
      const atoms = getAtomCounts(mf);

      if (Object.keys(atoms).length === 0) {
        correlations = correlations.filter(correlation => !correlation.pseudo);
      } // add pseudo correlations


      correlations = addPseudoCorrelations(correlations, atoms); // remove pseudo correlations to be replaced by equivalences

      correlations = replacePseudoCorrelationsByEquivalences(correlations, atoms); // remove pseudo correlations which are out of limit, clean up links and proton counts

      correlations = checkPseudoCorrelations(correlations, atoms);
      return correlations;
    }

    /**
     * Removes non-pseudo correlations which signal id can not be found or have no links anymore.
     *
     * @param {Values} values
     * @param {Experiment1DSignals} signals1D
     * @param {Experiment2DSignals} signals2D
     */

    function removeObsoleteLinksAndNotLinkedCorrelations(correlations, signals1D, signals2D) {
      const _correlations = correlations.filter(correlation => !correlation.pseudo);

      const removeList = _correlations.slice();

      _correlations.forEach(correlation => {
        for (const link of correlation.link) {
          if (link.experimentType === '1d') {
            // search in 1D data
            if (lodashGet(signals1D, link.atomType[0], []).some(signal1D => signal1D.signal.id === link.signal.id)) {
              const index = removeList.indexOf(correlation);

              if (index >= 0) {
                removeList.splice(index, 1);
              }
            } else if (!link.pseudo) {
              // remove obsolete link to not anymore existing signal
              removeLink(correlation, link.id);
            }
          } else if (lodashGet(signals2D, `${link.experimentType}`, []).some(signal2D => signal2D.signal.id === link.signal.id)) {
            // search in 2D data
            const index = removeList.indexOf(correlation);

            if (index >= 0) {
              removeList.splice(index, 1);
            }
          } else if (!link.pseudo) {
            // remove obsolete link to not anymore existing signal
            removeLink(correlation, link.id);
          }
        }
      });

      removeList.forEach(correlation => {
        const index = correlations.indexOf(correlation); // in case we already removed previously

        if (index >= 0) {
          correlations.splice(index, 1);
        }
      });
      return correlations;
    }

    /**
     * Checks whether an atom type key in attachments already exists.
     *
     * @param {Correlation} correlation
     * @param {string} atomType
     */
    function hasAttachmentAtomType(correlation, atomType) {
      return Boolean(correlation.attachment[atomType] && correlation.attachment[atomType].length > 0);
    }

    /**
     * Creates an attachment array for a certain atom type in a correlation.
     *
     * @param {Correlation} correlation
     * @param {string} atomType
     */

    function addAttachmentAtomType(correlation, atomType) {
      if (!hasAttachmentAtomType(correlation, atomType)) {
        correlation.attachment[atomType] = [];
      }

      return correlation;
    }

    /**
     * Adds an attachment for a certain atom type to a correlation.
     *
     * @param {Correlation} correlation
     * @param {string} atomType
     * @param {number} attachment
     */

    function addAttachment(correlation, atomType, attachment) {
      addAttachmentAtomType(correlation, atomType);

      if (!correlation.attachment[atomType].includes(attachment)) {
        correlation.attachment[atomType].push(attachment);
      }

      return correlation;
    }

    /**
     * Removes all attachments of a correlation.
     *
     * @param {Correlation} correlation
     */
    function removeAttachments(correlation) {
      correlation.attachment = {};
      return correlation;
    }

    /**
     * Sets the attachment information (indices of attached atoms).
     * And from that, the equivalence value for protons can be set too.
     *
     * @param {Values} values
     */

    function setAttachmentsAndProtonEquivalences(correlations) {
      // update attachment information between heavy atoms and protons via HSQC or HMQC
      for (const correlation of correlations) {
        // remove previous set attachments
        removeAttachments(correlation); // add attachments

        const linksFiltered = correlation.link.filter(link => link.experimentType === 'hsqc' || link.experimentType === 'hmqc');

        for (const link of linksFiltered) {
          const otherAtomType = link.atomType[link.axis === 'x' ? 1 : 0];

          for (let matchIndex of link.match) {
            addAttachment(correlation, otherAtomType, matchIndex);
          }
        }
      } // set previously set equivalences of protons to 0


      for (const correlation of correlations) {
        if (correlation.atomType === 'H') {
          correlation.equivalence = 0;
        }
      } // reset previously set proton equivalences and set new ones
      // check heavy atoms with an unambiguous protons count


      for (const correlation of correlations) {
        if (correlation.atomType !== 'H' && correlation.protonsCount.length === 1 && hasAttachmentAtomType(correlation, 'H')) {
          const {
            equivalence,
            protonsCount
          } = correlation;
          let equivalences = 1;

          if (protonsCount[0] === 3) {
            equivalences = 3;
          } else if (protonsCount[0] === 2) {
            equivalences = 2;
          }

          const sharedEquivalences = equivalence * equivalences / correlation.attachment.H.length;

          for (const attachedProtonIndex of correlation.attachment.H) {
            correlations[attachedProtonIndex].equivalence += sharedEquivalences;
          }
        }
      } // set unchanged equivalence of protons back to 1


      for (const correlation of correlations) {
        if (correlation.atomType === 'H' && correlation.equivalence === 0) {
          correlation.equivalence = 1;
        }
      }

      return correlations;
    }

    /**
     * Sets the origin (default) label for each correlation, e.g. C1 or H2, depending on its order.
     *
     * @param {Values} values
     */

    function setLabels(correlations) {
      const atomTypeCounts = {};
      correlations.forEach(correlation => {
        if (!lodashGet(atomTypeCounts, correlation.atomType, false)) {
          atomTypeCounts[correlation.atomType] = 0;
        }

        atomTypeCounts[correlation.atomType]++;
        correlation.label.origin = `${correlation.atomType}${atomTypeCounts[correlation.atomType]}`;
      });
      return correlations;
    }

    /**
     * Adds an index to the match array of a link.
     *
     * @param {Link} link
     * @param {number} index
     */
    function addMatch(link, index) {
      if (!link.match.includes(index)) {
        link.match.push(index);
      }

      return link;
    }

    /**
     * Removes all match indices in a link.
     *
     * @param {Link} link
     */
    function removeMatches(link) {
      link.match = [];
      return link;
    }

    /**
     * Sets the match indices for each link within a correlation.
     *
     * @param {Values} values
     */

    function setMatches(correlations) {
      correlations.forEach(correlation => {
        correlation.link.forEach(link => {
          // remove previously added matches
          removeMatches(link); // add matches

          const otherAtomType = link.axis === 'x' ? link.atomType[1] : link.atomType[0];
          getCorrelationsByAtomType(correlations, otherAtomType).forEach(correlationOtherAtomType => {
            if (correlation.id !== correlationOtherAtomType.id) {
              const correlationIndexOtherAtomType = getCorrelationIndex(correlations, correlationOtherAtomType);
              correlationOtherAtomType.link.forEach(linkOtherAtomType => {
                // check for correlation match and avoid possible duplicates
                if (linkOtherAtomType.experimentType === link.experimentType && linkOtherAtomType.experimentID === link.experimentID && lodashIsEqual(linkOtherAtomType.atomType, link.atomType) && linkOtherAtomType.signal.id === link.signal.id && linkOtherAtomType.axis !== link.axis) {
                  addMatch(link, correlationIndexOtherAtomType);
                }
              });
            }
          });
        });
      }); // remove links without any matches

      correlations.forEach(correlation => {
        const linksToRemove = correlation.link.filter(link => {
          var _a;

          return link.match.length === 0 && link.experimentType !== '1d' && !((_a = link.edited) === null || _a === void 0 ? void 0 : _a.moved);
        });
        linksToRemove.forEach(link => removeLink(correlation, link.id));
      });
      return correlations;
    }

    /**
     * Sorts the correlations according to its atom type value and signal delta.
     *
     * @param {Values} values
     */

    function sortCorrelations(correlations) {
      const compareAtomTypes = (atomType1, atomType2) => {
        // C and H highest priority
        if (atomType1 === 'C') {
          return -1;
        }

        if (atomType2 === 'C') {
          return 1;
        }

        if (atomType1 === 'H') {
          return -1;
        }

        if (atomType2 === 'H') {
          return 1;
        } // alphabetical sort


        if (atomType1 < atomType2) {
          return -1;
        }

        if (atomType1 > atomType2) {
          return 1;
        }

        return 0;
      };

      const compareCorrelations = (corr1, corr2) => {
        if (!corr1.pseudo && !corr2.pseudo && corr1.link.length > 0 && corr2.link.length > 0) {
          const corr1Delta = getCorrelationDelta(corr1);
          const corr2Delta = getCorrelationDelta(corr2);

          if (corr1Delta !== undefined && corr2Delta !== undefined) {
            if (corr1Delta < corr2Delta) {
              return -1;
            } else if (corr1Delta > corr2Delta) {
              return 1;
            }
          }
        }

        if (!corr1.pseudo && corr2.pseudo) {
          return -1;
        }

        if (corr1.pseudo && !corr2.pseudo) {
          return 1;
        }

        if (corr1.label.origin < corr2.label.origin) {
          return -1;
        }

        if (corr1.label.origin > corr2.label.origin) {
          return 1;
        }

        return 0;
      };

      let sortedCorrelations = [];
      const atomTypes = correlations.map(correlation => correlation.atomType).filter((atomType, i, a) => a.indexOf(atomType) === i);
      atomTypes.sort(compareAtomTypes);
      atomTypes.forEach(atomType => {
        const correlationsAtomType = getCorrelationsByAtomType(correlations, atomType);
        correlationsAtomType.sort(compareCorrelations);
        sortedCorrelations = sortedCorrelations.concat(correlationsAtomType);
      });
      return sortedCorrelations;
    }

    /**
     * Builds the correlation data values from given input spectra and options.
     * @param {Spectra} spectra
     * @param {Options} options
     */

    function buildValues(spectra, options) {
      const {
        tolerance = {},
        mf = '',
        values: prevValues = []
      } = options;
      const signals = getSignals(spectra);

      let _correlations = prevValues ? prevValues.slice() : [];

      if (options.skipDataUpdate !== true) {
        // remove obsolete links/correlations
        _correlations = removeObsoleteLinksAndNotLinkedCorrelations(_correlations, signals.signals1D, signals.signals2D); // add signals from either 1D or 2D if not already existing as correlation
        // if a signal already exists then add a link within matched correlation

        _correlations = addFromData(_correlations, signals.signals1D, signals.signals2D, tolerance);
      } else {
        // in case an external movement has led to en empty link array within a correlation
        _correlations = _correlations.filter(correlation => correlation.link.length > 0 || correlation.pseudo);
      } // set the number of attached protons via DEPT or edited HSQC


      _correlations = setProtonsCountFromData(_correlations, signals.signalsDEPT, signals.signals2D, tolerance); // sort by atom type and shift value

      _correlations = sortCorrelations(_correlations); // link signals via matches to same 2D signal: e.g. 13C -> HSQC <- 1H

      setMatches(_correlations); // set attachments via HSQC or HMQC

      setAttachmentsAndProtonEquivalences(_correlations); // update pseudo correlation

      _correlations = updatePseudoCorrelations(_correlations, mf); // set labels

      setLabels(_correlations);
      return _correlations;
    }

    /**
     * Builds the correlation data from spectra data and some options.
     *
     * @param {Spectra} spectra
     * @param {Options} options
     */

    function buildCorrelationData(spectra, options) {
      const values = spectra ? buildValues(spectra, options) : [];
      delete options.values;
      delete options.skipDataUpdate;
      return {
        values,
        options,
        state: buildState(values, options.mf || '')
      };
    }

    /**
     * Adds a link to a correlation.
     *
     * @param {Correlation} correlation
     * @param {Link} link
     */
    function addLink(correlation, link) {
      correlation.link.push(link);
      return correlation;
    }

    function createMapPossibleAssignment(expandMap, props) {
      const {
        restrictionByCS,
        predictions,
        targets
      } = props;
      const {
        tolerance: toleranceCS,
        chemicalShiftRestriction
      } = restrictionByCS;
      const atomTypes = Object.keys(predictions);

      for (const atomType of atomTypes) {
        let errorAbs = toleranceCS[atomType];
        let predictionByAtomType = predictions[atomType];
        let targetByAtomType = targets[atomType];
        if (!expandMap[atomType]) expandMap[atomType] = {};

        for (const diaID in predictionByAtomType) {
          let prediction = predictionByAtomType[diaID];
          expandMap[atomType][diaID] = [];

          if (targetByAtomType) {
            for (const targetID in targetByAtomType) {
              let target = targetByAtomType[targetID];
              const {
                nbAtoms,
                protonsCount: protonsCountFromPrediction
              } = prediction;
              const {
                integration,
                protonsCount
              } = target;
              const couldBeAssigned = !integration ? true : atomType === 'H' ? nbAtoms - integration < 1 : protonsCount.length > 0 ? protonsCount.some(count => protonsCountFromPrediction === count) : true;

              if (couldBeAssigned) {
                if (!chemicalShiftRestriction || typeof prediction.delta === 'undefined') {
                  // Chemical shift is not a restriction
                  expandMap[atomType][diaID].push(targetID);
                } else {
                  let targetDelta = getCorrelationDelta(target);

                  if (targetDelta === undefined) {
                    throw new Error(`Correlation has not delta`);
                  }

                  let distAfterLimit = Math.abs(prediction.delta - targetDelta - errorAbs);

                  if (distAfterLimit < 4 * errorAbs) {
                    expandMap[atomType][diaID].push(targetID);
                  }
                }
              }
            }
          }

          expandMap[atomType][diaID].push('*');
        }
      }

      return expandMap;
    }

    function groupCarbonTargetByIntegrationZone(activeDomainOnTarget, targets, correlations) {
      let targetID = activeDomainOnTarget[0];
      let {
        H: attachments = []
      } = targets[targetID].attachment;
      let targetByIntegral = [{
        targetIDs: [targetID],
        attachments: new Set(attachments)
      }];

      for (let i = 1; i < activeDomainOnTarget.length; i++) {
        let targetID = activeDomainOnTarget[i];
        let target = targets[targetID];
        let {
          H: attachments = []
        } = target.attachment;
        let alone = true;

        for (let group of targetByIntegral) {
          const pertain = attachments.some(attachment => group.attachments.has(attachment));

          if (pertain) {
            alone = false;
            group.targetIDs.push(targetID);

            for (let attachment of attachments) {
              group.attachments.add(attachment);
            }

            break;
          }
        }

        if (alone) {
          targetByIntegral.push({
            targetIDs: [targetID],
            attachments: new Set(attachments)
          });
        }
      }

      return targetByIntegral.map(t => ({
        atomType: 'C',
        targetIDs: t.targetIDs,
        integration: correlations ? Array.from(t.attachments).reduce((sum, index) => {
          return correlations[index].integration + sum;
        }, 0) : 0
      }));
    }

    function partialScore(partial, props) {
      const {
        diaIDPeerPossibleAssignment,
        infoByAtomTypes,
        restrictionByCS,
        predictions,
        targets,
        correlations
      } = props;
      const {
        tolerance: toleranceCS,
        useChemicalShiftScore
      } = restrictionByCS;
      let totalStarts = 0;
      let totalPartial = 0;
      let partialInverse = {};
      let activeDomainOnPrediction = {};
      const atomTypes = Object.keys(partial);

      for (const atomType of atomTypes) {
        let countStars = 0;
        const {
          nbAllowedUnAssigned
        } = infoByAtomTypes[atomType];
        const currentPartialInverse = {};
        const partialAssignment = partial[atomType] || [];
        partialInverse[atomType] = currentPartialInverse;
        activeDomainOnPrediction[atomType] = [];
        totalPartial += partialAssignment.length;

        for (let i = 0; i < partialAssignment.length; i++) {
          const targetID = partialAssignment[i];

          if (targetID && targetID !== '*') {
            activeDomainOnPrediction[atomType].push(i);

            if (!currentPartialInverse[targetID]) {
              currentPartialInverse[targetID] = [];
            }

            currentPartialInverse[targetID].push(diaIDPeerPossibleAssignment[atomType][i]);
          }

          if (targetID === '*') countStars++;
        }

        if (countStars > nbAllowedUnAssigned) return 0;
        totalStarts += countStars;
      }

      const activeDomainOnTarget = {};

      for (const atomType in partialInverse) {
        activeDomainOnTarget[atomType] = Object.keys(partialInverse[atomType]);
      }

      const valuesActiveDomainOnTarget = Object.values(activeDomainOnTarget);

      if (valuesActiveDomainOnTarget.reduce((sum, e) => e.length === 0 ? sum + 1 : sum, 0) === valuesActiveDomainOnTarget.length) {
        return 0;
      }

      const getPredictionByDiaID = getPrediction.bind({}, predictions); // check the integration

      const targetByIntegral = [];

      for (const atomType in partial) {
        if (atomType === 'C' && activeDomainOnTarget[atomType].length > 0) {
          targetByIntegral.push(...groupCarbonTargetByIntegrationZone(activeDomainOnTarget[atomType], targets[atomType], correlations));
        } else {
          for (let targetID of activeDomainOnTarget[atomType]) {
            targetByIntegral.push({
              atomType,
              targetIDs: [targetID],
              integration: targets.H[targetID].integration
            });
          }
        }
      }

      for (const group of targetByIntegral) {
        const {
          integration,
          atomType
        } = group;
        if (integration === undefined || isNaN(integration)) continue;
        let total = 0;

        for (let targetID of group.targetIDs) {
          let targetToSource = partialInverse[atomType][targetID];

          for (const diaID of targetToSource) {
            const {
              prediction,
              atomType: atomOfPrediction
            } = getPredictionByDiaID(diaID);
            if (atomType === atomOfPrediction) total += prediction.allHydrogens;
          }
        }

        if (total - integration >= 5) {
          return 0;
        }
      } //chemical shift score


      let count = 1;
      let chemicalShiftScore = 1;

      if (useChemicalShiftScore) {
        chemicalShiftScore = 0;
        count = 0;

        for (const atomType of Object.keys(partial)) {
          const partialPeerAtomType = partial[atomType];
          const targetsPeerAtomType = targets[atomType];

          for (let index = 0; index < partialPeerAtomType.length; index++) {
            const targetID = partialPeerAtomType[index];

            if (targetID && targetID !== '*') {
              count++;
              let diaID = diaIDPeerPossibleAssignment[atomType][index];
              let source = predictions[atomType][diaID];
              let target = targetsPeerAtomType[targetID];
              let error = toleranceCS[atomType]; // if (source.error) {
              //   error = Math.max(source.error, toleranceCS);
              // }

              if (typeof source.delta === 'undefined') {
                // Chemical shift is not a restriction
                chemicalShiftScore += 1;
              } else {
                const targetDelta = getCorrelationDelta(target);

                if (targetDelta === undefined) {
                  throw new Error('correlation has not delta');
                }

                let diff = Math.abs(source.delta - targetDelta);

                if (diff < error) {
                  //@TODO: check for a better discriminant
                  chemicalShiftScore += 1;
                } else {
                  diff = Math.abs(diff - error);
                  chemicalShiftScore += -0.25 / error * diff + 1;
                }
              }
            }
          }
        }

        if (count > 0) {
          chemicalShiftScore /= count;
        }
      }

      let scoreOn2D = 0;

      if (howManyActived(activeDomainOnTarget) > 1) {
        let andConstrains = {};
        let activeDomain = [];

        for (const atomType of Object.keys(activeDomainOnPrediction)) {
          activeDomain = activeDomain.concat(activeDomainOnPrediction[atomType].map(e => ({
            index: e,
            atomType
          })));
        }

        for (let i = 0; i < activeDomain.length; i++) {
          const {
            atomType: atomTypeI,
            index: indexI
          } = activeDomain[i];
          const predictionI = predictions[atomTypeI][diaIDPeerPossibleAssignment[atomTypeI][indexI]];

          for (let j = i + 1; j < activeDomain.length; j++) {
            const {
              atomType: atomTypeJ,
              index: indexJ
            } = activeDomain[j];
            const predictionJ = predictions[atomTypeJ][diaIDPeerPossibleAssignment[atomTypeJ][indexJ]];
            let pathLength = predictionI.pathLength[predictionJ.diaIDIndex];
            let isPossible = pathLength < 5;
            let partialI = partial[atomTypeI][indexI];
            let partialJ = partial[atomTypeJ][indexJ];
            if (!partialI || !partialJ) continue;
            let keyOnTargertMap = partialI > partialJ ? `${partialJ} ${partialI}` : `${partialI} ${partialJ}`;
            let areLinked = checkLinking({
              from: {
                targetID: partialI,
                atomType: atomTypeI
              },
              to: {
                targetID: partialJ,
                atomType: atomTypeJ
              }
            }, targets);
            let partialScore2D = isPossible ? areLinked ? 1 : 0 : !areLinked ? 1 : 0;
            andConstrains[keyOnTargertMap] = andConstrains[keyOnTargertMap] ? Math.max(andConstrains[keyOnTargertMap], partialScore2D) : partialScore2D;
          }
        }

        let sumAnd = 0;

        for (let key in andConstrains) {
          sumAnd += andConstrains[key];
        }

        scoreOn2D = sumAnd / (activeDomain.length * (activeDomain.length - 1) / 2);
      }

      const penaltyByStarts = totalStarts / totalPartial;
      if (chemicalShiftScore === 0) return scoreOn2D - penaltyByStarts;
      if (scoreOn2D === 0) return chemicalShiftScore - penaltyByStarts;
      return (chemicalShiftScore + scoreOn2D) / 2 - penaltyByStarts;
    }

    function checkLinking(partials, correlations) {
      const {
        from,
        to
      } = partials;
      if (from.targetID === to.targetID) return true;
      let correlationI = correlations[from.atomType][from.targetID];
      let correlationJ = correlations[to.atomType][to.targetID];

      for (const linkJ of correlationJ.link) {
        for (const link of correlationI.link) {
          if (link.signal.id === linkJ.signal.id) return true;
        }
      }

      return false;
    }

    function getPrediction(predictions, diaID) {
      const atomTypes = Object.keys(predictions);

      for (const atomType of atomTypes) {
        const predictionByAtomType = predictions[atomType];
        if (!predictionByAtomType) throw new Error(`prediction by ${atomType}`);

        if (predictionByAtomType[diaID]) {
          return {
            atomType,
            prediction: predictionByAtomType[diaID]
          };
        }
      }

      throw new Error(`There is not prediction for ${diaID}`);
    }

    function howManyActived(actived) {
      let sum = 0;

      for (const atom in actived) {
        sum += actived[atom].length;
      }

      return sum;
    }

    function exploreTree(props, infoByAtomTypes, partial, store) {
      const {
        currentAtomTypes,
        restrictionByCS,
        timeout,
        timeStart,
        maxSolutions,
        targets,
        predictions,
        correlations,
        lowerBoundScore,
        possibleAssignmentMap,
        diaIDPeerPossibleAssignment
      } = props;
      const currentDate = new Date();

      if (currentDate.getTime() - timeStart > timeout) {
        return store;
      }

      for (const atomType of currentAtomTypes) {
        const {
          currentIndex,
          nSources
        } = infoByAtomTypes[atomType];

        if (currentIndex >= nSources - 1 && partial[atomType][currentIndex] !== null) {
          continue;
        }

        const diaID = diaIDPeerPossibleAssignment[atomType][currentIndex];
        const possibleAssignments = possibleAssignmentMap[atomType][diaID];

        for (let targetID of possibleAssignments) {
          partial[atomType][currentIndex] = targetID;
          let score = partialScore(partial, {
            diaIDPeerPossibleAssignment,
            infoByAtomTypes,
            restrictionByCS,
            predictions,
            correlations,
            targets
          });

          if (score === 0) {
            continue;
          }

          if (isLastOne(currentAtomTypes, infoByAtomTypes) && score >= lowerBoundScore) {
            addSolution(store, {
              predictions,
              partial,
              score,
              maxSolutions
            });
          } else {
            const newInfo = JSON.parse(JSON.stringify(infoByAtomTypes));
            newInfo[atomType].currentIndex += 1;
            exploreTree({
              currentAtomTypes,
              restrictionByCS,
              timeout,
              timeStart,
              maxSolutions,
              targets,
              predictions,
              correlations,
              lowerBoundScore,
              possibleAssignmentMap,
              diaIDPeerPossibleAssignment
            }, newInfo, JSON.parse(JSON.stringify(partial)), store);
          }
        }
      }
    }

    function addSolution(store, props) {
      let {
        score,
        maxSolutions,
        partial,
        predictions
      } = props;
      score /= doubleAssignmentPenalty(partial, predictions);
      let solution = {
        assignment: JSON.parse(JSON.stringify(partial)),
        score
      };

      if (store.nSolutions >= maxSolutions) {
        if (solution.score > store.solutions.last().score) {
          store.solutions.pollLast();
          store.solutions.add(solution);
        }
      } else {
        store.solutions.add(solution);
        store.nSolutions++;
      }
    }

    function isLastOne(currentAtomTypes, infoByAtomTypes) {
      let lastOne = true;

      for (const atomType of currentAtomTypes) {
        const {
          currentIndex,
          nSources
        } = infoByAtomTypes[atomType];
        lastOne = lastOne && currentIndex >= nSources - 1;
      }

      return lastOne;
    }

    function doubleAssignmentPenalty(partial, predictions) {
      let nbDoubleAssignment = 0;

      for (const atomType in predictions) {
        const nbSources = Object.keys(predictions[atomType]).length;
        let assignments = new Set(partial[atomType]);
        nbDoubleAssignment += nbSources - assignments.size;
      }

      return nbDoubleAssignment > 0 ? 2 * nbDoubleAssignment : 1;
    }

    function isSpectraData1D(spectrum) {
      return 'ranges' in spectrum;
    }

    function searchIndices(signalId, spectra) {
      for (let spectrumIndex = 0; spectrumIndex < spectra.length; spectrumIndex++) {
        const spectrum = spectra[spectrumIndex];
        const data = isSpectraData1D(spectrum) ? spectrum.ranges : spectrum.zones;

        for (let elementIndex = 0; elementIndex < data.length; elementIndex++) {
          const signals = data[elementIndex].signals || [];

          for (let signalIndex = 0; signalIndex < signals.length; signalIndex++) {
            if (signalId === signals[signalIndex].id) {
              return {
                spectrumIndex,
                signalIndex,
                elementIndex
              };
            }
          }
        }
      }

      throw new Error(`There is not a signal with ${signalId} ID`);
    }

    const comparator = (a, b) => {
      return b.score - a.score;
    };

    const predictor = {
      H: predictProton,
      C: predictCarbon
    };

    function checkNMRSignal1D(signals) {
      const keys = ['nbAtoms', 'diaIDs', 'atoms'];

      for (const signal of signals) {
        for (let key of keys) {
          if (!signal[key]) throw new Error(`property ${key} does not exist`);
        }
      }
    }

    const getAllHydrogens = {
      C: (m, i) => m.getAllHydrogens(i),
      H: () => 1
    };
    async function buildAssignments(props) {
      const {
        spectra,
        molecule,
        restrictionByCS,
        timeout,
        minScore,
        nbAllowedUnAssigned = {},
        maxSolutions,
        correlations,
        assignmentOrder,
        predictionOptions,
        predictions: inputPrediction = {},
        targets
      } = props;
      let date = new Date();
      let timeStart = date.getTime();
      let lowerBoundScore = minScore;
      let store = {
        solutions: new TreeSet$1(comparator),
        nSolutions: 0
      };
      const pathLengthMatrix = getConnectivityMatrix(molecule, {
        pathLength: true
      });
      let infoByAtomType = {};
      const predictions = {};
      let possibleAssignmentMap = {};
      let diaIDPeerPossibleAssignment = {};

      for (const atomTypesToPredict of assignmentOrder) {
        for (const atomType of atomTypesToPredict) {
          const options = predictionOptions[atomType];
          const predictedSignals = inputPrediction[atomType];
          let {
            joinedSignals
          } = predictedSignals ? {
            joinedSignals: predictedSignals
          } : await predictor[atomType](molecule, options);
          checkNMRSignal1D(joinedSignals);
          if (!predictions[atomType]) predictions[atomType] = {};
          let totalHydrogens = 0;

          for (let prediction of joinedSignals) {
            const diaID = prediction.diaIDs[0];
            const index = prediction.atoms[0];
            const allHydrogens = getAllHydrogens[atomType](molecule, index);
            totalHydrogens += prediction.nbAtoms * allHydrogens;
            predictions[atomType][diaID] = { ...prediction,
              diaIDIndex: index,
              allHydrogens: prediction.nbAtoms * allHydrogens,
              protonsCount: allHydrogens,
              pathLength: pathLengthMatrix[index]
            };
          }

          for (let diaID in predictions[atomType]) {
            predictions[atomType][diaID].allHydrogens *= 100 / totalHydrogens;
          }

          infoByAtomType[atomType] = {
            nSources: joinedSignals.length,
            currentIndex: 0,
            nbAllowedUnAssigned: nbAllowedUnAssigned[atomType] || 0
          };
        }

        possibleAssignmentMap = createMapPossibleAssignment(possibleAssignmentMap, {
          restrictionByCS,
          predictions,
          targets
        });
        diaIDPeerPossibleAssignment = {};

        for (const atomType in possibleAssignmentMap) {
          diaIDPeerPossibleAssignment[atomType] = Object.keys(possibleAssignmentMap[atomType]);
        }

        let sourceOfPartials = getSourceOfPartials(store, infoByAtomType, atomTypesToPredict);
        store = {
          solutions: new TreeSet$1(comparator),
          nSolutions: 0
        };

        for (let partial of sourceOfPartials) {
          exploreTree({
            currentAtomTypes: atomTypesToPredict,
            restrictionByCS,
            timeout,
            timeStart,
            targets,
            predictions,
            correlations,
            maxSolutions,
            lowerBoundScore,
            possibleAssignmentMap,
            diaIDPeerPossibleAssignment
          }, infoByAtomType, partial, store);
        }
      }

      return annotateSpectraData({
        store,
        spectra,
        diaIDPeerPossibleAssignment,
        targets
      });
    }

    function annotateSpectraData(input) {
      var _a;

      const {
        store,
        spectra,
        diaIDPeerPossibleAssignment,
        targets
      } = input;
      const {
        solutions
      } = store;
      const mapSignalId = {};
      const atomTypes = Object.keys(targets);

      for (const atomType of atomTypes) {
        const targetByAtomType = targets[atomType];

        for (const targetId in targetByAtomType) {
          let target = targetByAtomType[targetId];

          for (const link of target.link) {
            const signalId = link.signal.id;
            if (mapSignalId[signalId]) continue;
            mapSignalId[link.signal.id] = searchIndices(signalId, spectra);
          }
        }
      }

      const result = [];

      for (let solution of solutions.elements) {
        const spectraResult = JSON.parse(JSON.stringify(spectra));
        const {
          assignment,
          score
        } = solution;
        const atomTypes = Object.keys(assignment);

        for (const atomType of atomTypes) {
          const targetByAtomType = targets[atomType];
          const assignmentPeerAtomType = assignment[atomType];

          for (let index = 0; index < assignmentPeerAtomType.length; index++) {
            const targetID = assignmentPeerAtomType[index];
            if (targetID === '*' || !targetID) continue;
            const target = targetByAtomType[targetID];
            const diaId = diaIDPeerPossibleAssignment[atomType][index];

            for (let link of target.link) {
              const {
                spectrumIndex,
                elementIndex,
                signalIndex
              } = mapSignalId[link.signal.id];
              const spectrum = spectraResult[spectrumIndex];

              if (isSpectraData1D(spectrum)) {
                let {
                  ranges
                } = spectrum;
                let range = ranges[elementIndex];
                let signal = range.signals[signalIndex];
                if (!signal.diaIDs) signal.diaIDs = [];
                signal.diaIDs.push(diaId);
              } else {
                const axis = link.axis;
                const signal = spectrum.zones[elementIndex].signals[signalIndex];
                if (!signal[axis].diaIDs) signal[axis].diaIDs = [];
                (_a = signal[axis].diaIDs) === null || _a === void 0 ? void 0 : _a.push(diaId);
              }
            }
          }
        }

        result.push({
          score,
          assignment: spectraResult
        });
      }

      return result;
    }

    function getSourceOfPartials(store, infoByAtomType, currentAtoms) {
      return store.nSolutions > 0 ? store.solutions.elements.map(e => {
        let currentAssignment = e.assignment;

        for (const atom of currentAtoms) {
          currentAssignment[atom] = fillPartial(infoByAtomType[atom].nSources);
        }

        return currentAssignment;
      }) : initializePartials(infoByAtomType, currentAtoms);
    }

    function initializePartials(infoByAtomType, currentAtoms) {
      const partial = {};
      const atomsType = Object.keys(infoByAtomType);

      for (const atom of atomsType) {
        const value = currentAtoms.includes(atom) ? null : '*';
        partial[atom] = fillPartial(infoByAtomType[atom].nSources, value);
      }

      return [partial];
    }

    function fillPartial(nSources) {
      let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
      const partial = new Array(nSources);

      for (let i = 0; i < nSources; i++) {
        partial[i] = value;
      }

      return partial;
    }

    function checkIDs() {
      let input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
      let inputClone = JSON.parse(JSON.stringify(input));
      let spectra = [];

      for (const spectraData of inputClone) {
        if (!('info' in spectraData)) {
          throw new Error('each spectrum should contain info properties with nucleus information');
        }

        const {
          info,
          id
        } = spectraData;

        if (isSpectraData1D(spectraData)) {
          let ranges = addIDs(spectraData.ranges);
          spectra.push({
            id,
            info,
            ranges
          });
        } else {
          let data = addIDs(spectraData.zones);
          spectra.push({
            id,
            info,
            zones: data
          });
        }
      }

      return spectra;
    }
    function hasIDs(data) {
      for (const element of data) {
        if (!element.id) throw new Error('A range/zone has not an ID');

        for (let signal of element.signals || []) {
          if (!signal.id) throw new Error('A signal has not an ID');
        }
      }
    }
    function addIDs(data) {
      for (const element of data) {
        if (!element.id) element.id = v4();

        for (let signal of element.signals || []) {
          if (!signal.id) signal.id = v4();
        }
      }

      hasIDs(data);
      return data;
    }

    function formatData() {
      let input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
      let inputClone = JSON.parse(JSON.stringify(input));
      let spectra = [];

      for (const spectraData of inputClone) {
        const {
          id,
          info
        } = spectraData;

        if (isSpectraData1D(spectraData)) {
          const ranges = rescaleIntegration({
            id,
            info,
            ranges: spectraData.ranges
          });
          spectra.push({
            id,
            info,
            ranges: {
              values: ranges
            }
          });
        } else {
          spectra.push({
            id,
            info,
            zones: {
              values: spectraData.zones
            }
          });
        }
      }

      return spectra;
    }

    function rescaleIntegration(spectrum) {
      if (spectrum.info.nucleus !== '1H') return spectrum.ranges;
      let totalIntegration = spectrum.ranges.reduce((total, range) => range.integration ? total + range.integration : total, 0);

      for (let range of spectrum.ranges) {
        if (range.integration) {
          range.integration *= 100 / totalIntegration;

          if (range.signals) {
            const totalSignalIntegration = range.signals.reduce((total, signal) => signal.integration ? total + signal.integration : total, 0);

            for (let signal of range.signals) {
              if (signal.integration) {
                signal.integration *= range.integration / totalSignalIntegration;
              } else {
                signal.integration = range.integration;
              }
            }
          }
        }
      }

      return spectrum.ranges;
    }

    function getIntegrationOfAttachedProtons(target, correlations) {
      const {
        H: attachment = []
      } = target.attachment;
      let integration = 0;

      for (const match of attachment) {
        const correlation = correlations[match];
        integration += Number(correlation.link[0].signal.integration);
      }

      return integration;
    }

    function getTargetsAndCorrelations(spectra) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      //add indirect links, if a carbon C1 is attached to a proton H1 that correlating
      //with carbon C2, so the carbon C1 and C2 are also correlating
      const {
        tolerance = {
          C: 0.25,
          H: 0.05
        }
      } = options;
      const spectraData = formatData(spectra);
      const {
        values: correlations
      } = buildCorrelationData(spectraData, {
        tolerance
      });
      let targets = {};

      for (const correlation of correlations) {
        if (correlation.pseudo) continue;
        const {
          id: targetID,
          atomType
        } = correlation;
        if (!targets[atomType]) targets[atomType] = {};
        targets[atomType][targetID] = correlation;

        if (atomType === 'H') {
          targets[atomType][targetID].integration = correlation.link[0].signal.integration;
        } else {
          targets[atomType][targetID].integration = getIntegrationOfAttachedProtons(correlation, correlations);
        }
      }

      return {
        targets,
        correlations
      };
    }

    /**
     * if hsqc is present in experimentTypes we can just predict 13C
     * spectrum and try to assign the carbons first.
     * @param {*} correlations
     * @param {*} justAssign
     */
    function getWorkFlow(correlations) {
      let justAssign = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
      const experimentTypes = extractExperimentType(correlations);
      const {
        hasHSQC,
        types
      } = experimentTypes;

      if (justAssign.length > 0) {
        return {
          assignmentOrder: justAssign,
          experimentTypes
        };
      }

      const assignmentOrder = [];

      if (hasHSQC) {
        assignmentOrder.push(['C'], ['H']);
      } else {
        assignmentOrder.push(types.filter(type => type === 'H' || type === 'C'));
      }

      return {
        assignmentOrder,
        experimentTypes
      };
    }

    function extractExperimentType(correlations) {
      const types = [];

      for (const correlation of correlations) {
        let experimentType = correlation.experimentType;

        if (experimentType === '1d') {
          experimentType = `${correlation.atomType.toUpperCase()}`;
        }

        if (!types.includes(experimentType)) {
          types.push(experimentType);
        }

        for (const link of correlation.link) {
          experimentType = link.experimentType;

          if (experimentType === '1d') {
            experimentType = `${link.atomType[0].toUpperCase()}`;
          }

          if (!types.includes(experimentType)) {
            types.push(experimentType);
          }
        }
      }

      return {
        types,
        hasProton: types.includes('H'),
        hasCarbon: types.includes('C'),
        hasHSQC: types.includes('hsqc')
      };
    }

    async function getAssignments(input) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        restrictionByCS = {},
        justAssign,
        minScore = 0.01,
        maxSolutions = 10,
        nbAllowedUnAssigned,
        timeout = 6000,
        predictionOptions = {},
        predictions = {},
        correlation: correlationOptions = {}
      } = options;
      const {
        tolerance = {
          H: 0.2,
          C: 1
        },
        useChemicalShiftScore = false,
        chemicalShiftRestriction = true
      } = restrictionByCS;
      const molecule = input.molecule;
      if (!molecule) throw new Error('It is needed a molecule to assign');
      molecule.addImplicitHydrogens();
      addDiastereotopicMissingChirality(molecule);
      const spectra = checkIDs(input.spectra);
      const {
        targets,
        correlations
      } = getTargetsAndCorrelations(spectra, correlationOptions);
      const {
        assignmentOrder
      } = getWorkFlow(correlations, justAssign);
      const solutions = await buildAssignments({
        restrictionByCS: {
          tolerance,
          useChemicalShiftScore,
          chemicalShiftRestriction
        },
        spectra,
        molecule,
        timeout,
        minScore,
        maxSolutions,
        assignmentOrder,
        nbAllowedUnAssigned,
        correlations,
        targets,
        predictionOptions,
        predictions
      });
      return solutions;
    }

    /**
     * Return
     * @param {*} signal
     */
    function signalMultiplicityPattern(signal) {
      let js = signal.js;
      let pattern = '';

      if (js && js.length > 0) {
        for (let coupling of js) {
          pattern += coupling.multiplicity;
        }
      } else if (signal.delta) {
        pattern = 's';
      } else {
        pattern = 'm';
      }

      return pattern;
    }

    const globalOptions = {
      h: {
        nucleus: '1H',
        nbDecimalDelta: 2,
        nbDecimalJ: 1,
        observedFrequency: 400
      },
      c: {
        nucleus: '13C',
        nbDecimalDelta: 1,
        nbDecimalJ: 1,
        observedFrequency: 100
      },
      f: {
        nucleus: '19F',
        nbDecimalDelta: 2,
        nbDecimalJ: 1,
        observedFrequency: 400
      }
    };
    function rangesToACS(ranges) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      if (!options.nucleus) options.nucleus = '1H';
      const nucleus = options.nucleus.toLowerCase().replace(/[0-9]/g, '');
      const defaultOptions = globalOptions[nucleus];
      options = { ...defaultOptions,
        ascending: false,
        format: 'IMJA',
        ...options
      };
      ranges = JSON.parse(JSON.stringify(ranges));

      if (options.ascending === true) {
        ranges.sort((a, b) => {
          const fromA = Math.min(a.from, a.to);
          const fromB = Math.min(b.from, b.to);
          return fromA - fromB;
        });
      }

      let acsString = formatAcs(ranges, options);
      if (acsString.length > 0) acsString += '.';
      return acsString;
    }

    function formatAcs(ranges, options) {
      let acs = spectroInformation(options);
      if (acs.length === 0) acs = 'δ ';
      const acsRanges = [];

      for (const range of ranges) {
        if (uselessKind(range.kind, options.filter)) continue;
        pushDelta(range, acsRanges, options);
      }

      if (acsRanges.length > 0) {
        return acs + acsRanges.join(', ');
      } else {
        return '';
      }
    }

    function spectroInformation(options) {
      const parenthesis = [];
      let strings = `${formatNucleus(options.nucleus)} NMR`;

      if (options.solvent) {
        parenthesis.push(formatMF(options.solvent));
      }

      if (options.observedFrequency) {
        parenthesis.push(`${(options.observedFrequency * 1).toFixed(0)} MHz`);
      }

      if (parenthesis.length > 0) {
        strings += ` (${parenthesis.join(', ')}): δ `;
      } else {
        strings += ': δ ';
      }

      return strings;
    }

    function pushDelta(range, acsRanges, options) {
      let strings = '';
      let parenthesis = [];
      const fromTo = [range.from, range.to];

      if (range.signals) {
        range.signals = range.signals.filter(signal => !uselessKind(signal.kind, options.filter));
      }

      if (range.signals && range.signals.length > 0) {
        let signals = range.signals;

        if (signals.length > 1) {
          if (options.ascending === true) {
            signals.sort((a, b) => {
              return a.delta - b.delta;
            });
          }

          strings += `${Math.min(...fromTo).toFixed(options.nbDecimalDelta)}-${Math.max(...fromTo).toFixed(options.nbDecimalDelta)}`;
          strings += ` (${getIntegral(range, options)}`;

          for (let signal of signals) {
            parenthesis = [];

            if (signal.delta !== undefined) {
              strings = appendSeparator(strings);
              strings += signal.delta.toFixed(options.nbDecimalDelta);
            }

            const range = {
              from: Number.MIN_SAFE_INTEGER,
              to: Number.MAX_SAFE_INTEGER
            };
            switchFormat(range, signal, parenthesis, options);
            if (parenthesis.length > 0) strings += ` (${parenthesis.join(', ')})`;
          }

          strings += ')';
        } else {
          parenthesis = [];

          if (signals[0].delta !== undefined) {
            strings += signals[0].delta.toFixed(options.nbDecimalDelta);
            switchFormat(range, signals[0], parenthesis, options);
            if (parenthesis.length > 0) strings += ` (${parenthesis.join(', ')})`;
          } else {
            strings += `${Math.min(...fromTo).toFixed(options.nbDecimalDelta)}-${Math.max(...fromTo).toFixed(options.nbDecimalDelta)}`;
            switchFormat(range, signals[0], parenthesis, options);
            if (parenthesis.length > 0) strings += ` (${parenthesis})`;
          }
        }
      } else {
        strings += `${Math.min(...fromTo).toFixed(options.nbDecimalDelta)}-${Math.max(...fromTo).toFixed(options.nbDecimalDelta)}`;
        const signal = {};
        switchFormat(range, signal, parenthesis, options);
        if (parenthesis.length > 0) strings += ` (${parenthesis.join(', ')})`;
      }

      acsRanges.push(strings);
    }

    function getIntegral(range, options) {
      let integration = '';

      if (range.pubIntegral) {
        integration = String(range.pubIntegral);
      } else if (range.integration) {
        const {
          nucleus
        } = options;
        integration = range.integration.toFixed(0) + nucleus[nucleus.length - 1];
      }

      return integration;
    }

    function pushIntegral(range, parenthesis, options) {
      let integration = getIntegral(range, options);
      if (integration.length > 0) parenthesis.push(integration);
    }

    function pushmultiplicityFromSignal(signal, parenthesis) {
      let multiplicity = signal.multiplicity;

      if (!multiplicity) {
        let joinedCouplings = signalJoinCouplings(signal, {
          tolerance: 0.05,
          ignoreDiaIDs: true
        });
        multiplicity = signalMultiplicityPattern(joinedCouplings);
      }

      if (multiplicity.length > 0) parenthesis.push(multiplicity);
    }

    function switchFormat(range, signal, parenthesis, options) {
      for (const char of options.format) {
        switch (char.toUpperCase()) {
          case 'I':
            pushIntegral(range, parenthesis, options);
            break;

          case 'M':
            pushmultiplicityFromSignal(signal, parenthesis);
            break;

          case 'A':
            pushAssignment(signal, parenthesis);
            break;

          case 'J':
            pushCoupling(signal, parenthesis, options);
            break;

          default:
            throw new Error(`Unknow format letter: ${char}`);
        }
      }
    }

    function formatMF(mf) {
      return mf.replace(/(?<num>[0-9]+)/g, '<sub>$<num></sub>');
    }

    function formatNucleus(nucleus) {
      return nucleus.replace(/(?<num>[0-9]+)/g, '<sup>$<num></sup>');
    }

    function appendSeparator(strings) {
      if (strings.length > 0 && !/ $/.exec(strings) && !/\($/.exec(strings)) {
        strings += ', ';
      }

      return strings;
    }

    function formatAssignment(assignment) {
      assignment = assignment.replace(/(?<num>[0-9]+)/g, '<sub>$<num></sub>');
      assignment = assignment.replace(/"(?<i>[^"]*)"/g, '<i>$<i></i>');
      return assignment;
    }

    function pushCoupling(signal, parenthesis, options) {
      if (Array.isArray(signal.js) && signal.js.length > 0) {
        signal.js.sort((a, b) => {
          return b.coupling - a.coupling;
        });
        let values = [];

        for (let j of signal.js) {
          if (j.coupling !== undefined) {
            values.push(j.coupling.toFixed(options.nbDecimalJ));
          }
        }

        if (values.length > 0) {
          parenthesis.push(`<i>J</i> = ${values.join(', ')} Hz`);
        }
      }
    }

    function pushAssignment(signal, parenthesis) {
      if (signal.assignment) {
        parenthesis.push(formatAssignment(signal.assignment));
      }
    }

    function uselessKind() {
      let kind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
      let filter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
      kind = kind.toLowerCase();
      if (filter && (kind === 'impurity' || kind === 'solvent')) return true;
      return false;
    }

    function addDummySignals(signals) {
      let newSignals = JSON.parse(JSON.stringify(signals));
      let nextAtomToAssign = signals.reduce((nextAtomToAssign, signal) => {
        const {
          atoms = []
        } = signal;
        return Math.max(...atoms) > nextAtomToAssign ? Math.max(...atoms) : nextAtomToAssign;
      }, 0) + 1;
      signals.forEach((signal, s) => {
        const {
          js: jCouplings = [],
          atoms: signalAssignment = [nextAtomToAssign++]
        } = signal;
        let {
          newCouplings,
          tempSignals
        } = checkCouplings(jCouplings, newSignals, signalAssignment, nextAtomToAssign + signals.length);
        if (tempSignals.length > 0) newSignals.push(...tempSignals);
        newSignals[s].js = newCouplings;
        newSignals[s].atoms = signalAssignment;
      });
      return newSignals.sort((a, b) => a.delta - b.delta);
    }

    function checkCouplings(jCouplings, signals, signalAssignment, nextAtomToAssign) {
      let tempSignals = [];
      const newCouplings = jCouplings.reduce((newCouplings, jCoupling) => {
        const {
          atoms = [],
          multiplicity,
          coupling
        } = jCoupling;

        if (atoms.length === 0) {
          if (coupling && multiplicity) {
            const nbLinks = couplingPatterns.indexOf(multiplicity);

            for (let i = 0; i < nbLinks; i++) {
              nextAtomToAssign++;
              tempSignals.push(formatSignal(coupling, [nextAtomToAssign], signalAssignment));
            }
          } else {
            newCouplings.push(jCoupling);
          }
        }

        return newCouplings;
      }, []);
      return {
        newCouplings,
        tempSignals
      };
    }

    function formatSignal(coupling, newSignalAssignment, signalAssignment) {
      return {
        delta: 100000,
        atoms: newSignalAssignment,
        js: [{
          coupling,
          atoms: signalAssignment
        }]
      };
    }

    /**
     * Create the xy object from an array of 1D signals.
     * @param signals Array of signals with assigned or unassigned couplings.
     */

    function hackSignalsToXY(signals) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let newSignals = addDummySignals(signals);
      return signalsToXY(newSignals, options);
    }

    function checkForSignals(ranges) {
      for (let range of ranges) {
        if (!range.signals) throw new Error('range has not signals');
      }
    }

    const defaultFromTo = function () {
      let nucleus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

      switch (nucleus.toUpperCase()) {
        case '13C':
          return {
            from: -5,
            to: 206
          };

        default:
          return {
            from: -0.5,
            to: 10.5
          };
      }
    };

    function rangesToXY(ranges) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      checkForSignals(ranges);
      let {
        frequency = 400,
        lineWidth = 1,
        nbPoints = 16 * 1024,
        shape = {
          kind: 'gaussian'
        }
      } = options;

      const addSpectrum = (a, b) => {
        for (let i = 0; i < nbPoints; i++) {
          a[i] += b[i];
        }
      };

      const {
        from,
        to
      } = getFromTo(ranges, options);
      const spectrumOptions = {
        to,
        from,
        nbPoints,
        shape,
        lineWidth,
        frequency
      };
      let spectrum = new Float64Array(nbPoints);

      for (const range of ranges) {
        const {
          integration,
          signals = []
        } = range;
        const {
          multiplicity: rangeMulplicity = ''
        } = range;

        if (rangeMulplicity === 'm' && signals.length < 1) {
          const {
            from,
            to
          } = range;
          signals.push({
            delta: (from + to) / 2,
            multiplicity: 'm'
          });
        }

        let rangeSpectrum = new Float64Array(nbPoints);

        for (const signal of signals) {
          const {
            multiplicity
          } = signal;
          let signalSpectrum = multiplicity === 'm' || multiplicity === 'b' || multiplicity === 'br s' ? broadPeakOrMultipletSpectrum([signal], spectrumOptions).y : hackSignalsToXY([signal], spectrumOptions).y;
          normalizeSpectrum(signalSpectrum, [signal]);
          addSpectrum(rangeSpectrum, signalSpectrum);
        }

        if (range.integration) {
          normalizeSpectrum(rangeSpectrum, signals, {
            integration
          });
        }

        addSpectrum(spectrum, rangeSpectrum);
      }

      return {
        x: xSequentialFill({
          from,
          to,
          size: nbPoints
        }),
        y: spectrum
      };
    }

    function broadPeakOrMultipletSpectrum(signals) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        lineWidth,
        frequency
      } = options;
      const spectrumGenerator = new SpectrumGenerator(options);
      const broadWidth = lineWidth * 3 / frequency;

      for (let signal of signals) {
        const {
          multiplicity,
          delta,
          integration = 1
        } = signal;

        if (multiplicity === 'b' || multiplicity === 'br s') {
          spectrumGenerator.addPeak({
            x: delta,
            y: integration,
            width: broadWidth
          });
        } else {
          const peaks = peaksOfMultiplet(delta, {
            lineWidth,
            frequency
          });
          spectrumGenerator.addPeaks(peaks);
        }
      }

      return spectrumGenerator.getSpectrum();
    }

    function peaksOfMultiplet(delta, options) {
      const {
        frequency,
        lineWidth,
        intensities = [1, 2, 5, 4, 5, 7, 5, 4, 5, 2, 1]
      } = options;
      const lineWidthPpm = lineWidth / frequency;
      const spaceBetweenPeaks = lineWidthPpm * 1.5;
      const peaks = [];
      const firstPeakPosition = delta - spaceBetweenPeaks * intensities.length / 2;

      for (let i = 0; i < intensities.length; i++) {
        peaks.push({
          x: firstPeakPosition + spaceBetweenPeaks * i,
          y: intensities[i],
          width: lineWidthPpm
        });
      }

      return peaks;
    }

    function normalizeSpectrum(spectrum, signals) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      const {
        integration = signals.reduce((acc, signal) => {
          const {
            integration = 1
          } = signal;
          return acc + integration;
        }, 0)
      } = options;
      const sum = spectrum.reduce((acc, element) => acc + element, 0);

      if (sum !== 0) {
        const norma = integration / sum * 1e6;

        for (let i = 0; i < spectrum.length; i++) {
          spectrum[i] *= norma;
        }
      }
    }

    function getFromTo(ranges, options) {
      const {
        from: defaultFrom,
        to: defaultTo
      } = defaultFromTo(options.nucleus);
      let rangesFrom = Number.MAX_SAFE_INTEGER;
      let rangesTo = Number.MIN_SAFE_INTEGER;

      for (const range of ranges) {
        for (const signal of range.signals || []) {
          if (rangesFrom > signal.delta) rangesFrom = signal.delta;
          if (rangesTo < signal.delta) rangesTo = signal.delta;
        }
      }

      const {
        from = Math.min(rangesFrom - 0.5, defaultFrom),
        to = Math.max(rangesTo + 0.5, defaultTo)
      } = options;
      return {
        from,
        to
      };
    }

    /**
     * Preparata, F. P., & Shamos, M. I. (2012). Computational geometry: an introduction. Springer Science & Business Media.
     * @param {Array} x - The array with x coordinates of the points.
     * @param {Array} y - The array with y coordinates of the points.
     * @return {Array} The indices of the points of anticlockwise lower convex hull
     * @private
     */
    function antiLowerConvexHull(x, y) {
      if (x.length !== y.length) {
        throw new RangeError('X and Y vectors has different dimensions');
      }

      const nbPoints = x.length - 1;
      if (nbPoints === 0) return [0];
      if (nbPoints === 1) return [0, 1];
      let currentPoint = 0;
      let result = new Array(x.length).fill(true);

      while (true) {
        const a = currentPoint;
        const b = moveOn(currentPoint, nbPoints, result);
        const c = moveOn(moveOn(currentPoint, nbPoints, result), nbPoints, result);
        const det = x[c] * (y[a] - y[b]) + x[a] * (y[b] - y[c]) + x[b] * (y[c] - y[a]);
        const leftTurn = det >= 0;

        if (leftTurn) {
          currentPoint = b;
        } else {
          result[b] = false;
          currentPoint = moveBack(currentPoint, nbPoints, result);
        }

        if (c === nbPoints) break;
      }

      return result.map((item, index) => item === false ? false : index).filter(item => item !== false);
    }
    /**
     * @param {number} currentPoint - The index of the current point to make the move
     * @param {number} nbPoints - The total number of points in the array
     * @param {Array} vector - The array with the points
     * @return {number} the index of the point after the move
     * @private
     */

    function moveBack(currentPoint, nbPoints, vector) {
      let counter = currentPoint - 1;

      while (vector[counter] === false) counter--;

      return currentPoint === 0 ? nbPoints : counter;
    }

    function moveOn(currentPoint, nbPoints, vector) {
      let counter = currentPoint + 1;

      while (vector[counter] === false) counter++;

      return currentPoint === nbPoints ? 0 : counter;
    }

    /**
     * Performs a global optimization of required parameters
     * It will return an object containing:
     * - `minFunctionValue`: The minimum value found for the objetive function
     * - `optima`: Array of Array of values for all the variables where the function reach its minimum value
     * - `iterations`: Number of iterations performed in the process
     * - `finalState`: Internal state allowing to continue optimization (initialState)
     * @param {function} objectiveFunction Function to evaluate. It should accept an array of variables
     * @param {Array} lowerBoundaries Array containing for each variable the lower boundary
     * @param {Array} upperBoundaries Array containing for each variable the higher boundary
     * @param {Object} [options={}]
     * @param {number} [options.iterations] - Number of iterations.
     * @param {number} [options.epsilon] - Tolerance to choose best current value.
     * @param {number} [options.tolerance] - Minimum tollerance of the function.
     * @param {number} [options.tolerance2] - Minimum tollerance of the function.
     * @param {Object} [options.initialState={}}] - finalState of previous optimization.
     * @return {Object} {finalState, iterations, minFunctionValue}
     * */

    function direct(objectiveFunction, lowerBoundaries, upperBoundaries) {
      let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
      const {
        iterations = 50,
        epsilon = 1e-4,
        tolerance = 1e-16,
        tolerance2 = 1e-12,
        initialState = {}
      } = options;

      if (objectiveFunction === undefined || lowerBoundaries === undefined || upperBoundaries === undefined) {
        throw new RangeError('There is something undefined');
      }

      lowerBoundaries = new Float64Array(lowerBoundaries);
      upperBoundaries = new Float64Array(upperBoundaries);

      if (lowerBoundaries.length !== upperBoundaries.length) {
        throw new Error('Lower bounds and Upper bounds for x are not of the same length');
      } //-------------------------------------------------------------------------
      //                        STEP 1. Initialization
      //-------------------------------------------------------------------------


      let n = lowerBoundaries.length;
      let diffBorders = upperBoundaries.map((x, i) => x - lowerBoundaries[i]);
      let {
        numberOfRectangles = 0,
        totalIterations = 0,
        unitaryCoordinates = [new Float64Array(n).fill(0.5)],
        middlePoint = new Float64Array(n).map((value, index) => {
          return lowerBoundaries[index] + unitaryCoordinates[0][index] * diffBorders[index];
        }),
        bestCurrentValue = objectiveFunction(middlePoint),
        fCalls = 1,
        smallerDistance = 0,
        edgeSizes = [new Float64Array(n).fill(0.5)],
        diagonalDistances = [Math.sqrt(n * Math.pow(0.5, 2))],
        functionValues = [bestCurrentValue],
        differentDistances = diagonalDistances,
        smallerValuesByDistance = [bestCurrentValue],
        choiceLimit = undefined
      } = initialState;

      if (initialState.originalCoordinates && initialState.originalCoordinates.length > 0) {
        bestCurrentValue = xMinValue(functionValues);
        choiceLimit = epsilon * Math.abs(bestCurrentValue) > 1e-8 ? epsilon * Math.abs(bestCurrentValue) : 1e-8;
        smallerDistance = getMinIndex(functionValues, diagonalDistances, choiceLimit, bestCurrentValue);
        unitaryCoordinates = initialState.originalCoordinates.slice();

        for (let j = 0; j < unitaryCoordinates.length; j++) {
          for (let i = 0; i < lowerBoundaries.length; i++) {
            unitaryCoordinates[j][i] = (unitaryCoordinates[j][i] - lowerBoundaries[i]) / diffBorders[i];
          }
        }
      }

      let iteration = 0; //-------------------------------------------------------------------------
      //                          Iteration loop
      //-------------------------------------------------------------------------

      while (iteration < iterations) {
        //----------------------------------------------------------------------
        //  STEP 2. Identify the set S of all potentially optimal rectangles
        //----------------------------------------------------------------------
        let S1 = [];
        let idx = differentDistances.findIndex( // eslint-disable-next-line no-loop-func
        e => e === diagonalDistances[smallerDistance]);
        let counter = 0;

        for (let i = idx; i < differentDistances.length; i++) {
          for (let f = 0; f < functionValues.length; f++) {
            if (functionValues[f] === smallerValuesByDistance[i] & diagonalDistances[f] === differentDistances[i]) {
              S1[counter++] = f;
            }
          }
        }

        let optimumValuesIndex, S3;

        if (differentDistances.length - idx > 1) {
          let a1 = diagonalDistances[smallerDistance];
          let b1 = functionValues[smallerDistance];
          let a2 = differentDistances[differentDistances.length - 1];
          let b2 = smallerValuesByDistance[differentDistances.length - 1];
          let slope = (b2 - b1) / (a2 - a1);
          let constant = b1 - slope * a1;
          let S2 = new Uint32Array(counter);
          counter = 0;

          for (let i = 0; i < S2.length; i++) {
            let j = S1[i];

            if (functionValues[j] <= slope * diagonalDistances[j] + constant + tolerance2) {
              S2[counter++] = j;
            }
          }

          let xHull = [];
          let yHull = [];

          for (let i = 0; i < counter; i++) {
            xHull.push(diagonalDistances[S2[i]]);
            yHull.push(functionValues[S2[i]]);
          }

          let lowerIndexHull = antiLowerConvexHull(xHull, yHull);
          S3 = [];

          for (let i = 0; i < lowerIndexHull.length; i++) {
            S3.push(S2[lowerIndexHull[i]]);
          }
        } else {
          S3 = S1.slice(0, counter);
        }

        optimumValuesIndex = S3; //--------------------------------------------------------------
        // STEPS 3,5: Select any rectangle j in S
        //--------------------------------------------------------------

        for (let k = 0; k < optimumValuesIndex.length; k++) {
          let j = optimumValuesIndex[k];
          let largerSide = xMaxValue(edgeSizes[j]);
          let largeSidesIndex = new Uint32Array(edgeSizes[j].length);
          counter = 0;

          for (let i = 0; i < edgeSizes[j].length; i++) {
            if (Math.abs(edgeSizes[j][i] - largerSide) < tolerance) {
              largeSidesIndex[counter++] = i;
            }
          }

          let delta = 2 * largerSide / 3;
          let bestFunctionValues = [];

          for (let r = 0; r < counter; r++) {
            let i = largeSidesIndex[r];
            let firstMiddleCenter = unitaryCoordinates[j].slice();
            let secondMiddleCenter = unitaryCoordinates[j].slice();
            firstMiddleCenter[i] += delta;
            secondMiddleCenter[i] -= delta;
            let firstMiddleValue = new Float64Array(firstMiddleCenter.length);
            let secondMiddleValue = new Float64Array(secondMiddleCenter.length);

            for (let i = 0; i < firstMiddleCenter.length; i++) {
              firstMiddleValue[i] = lowerBoundaries[i] + firstMiddleCenter[i] * diffBorders[i];
              secondMiddleValue[i] = lowerBoundaries[i] + secondMiddleCenter[i] * diffBorders[i];
            }

            let firstMinValue = objectiveFunction(firstMiddleValue);
            let secondMinValue = objectiveFunction(secondMiddleValue);
            fCalls += 2;
            bestFunctionValues.push({
              minValue: Math.min(firstMinValue, secondMinValue),
              index: r
            }); // [Math.min(firstMinValue, secondMinValue), r];

            unitaryCoordinates.push(firstMiddleCenter, secondMiddleCenter);
            functionValues.push(firstMinValue, secondMinValue);
          }

          let b = bestFunctionValues.sort((a, b) => a.minValue - b.minValue);

          for (let r = 0; r < counter; r++) {
            let u = largeSidesIndex[b[r].index];
            let ix1 = numberOfRectangles + 2 * (b[r].index + 1) - 1;
            let ix2 = numberOfRectangles + 2 * (b[r].index + 1);
            edgeSizes[j][u] = delta / 2;
            edgeSizes[ix1] = edgeSizes[j].slice();
            edgeSizes[ix2] = edgeSizes[j].slice();
            diagonalDistances[j] = xNorm(edgeSizes[j]);
            diagonalDistances[ix1] = diagonalDistances[j];
            diagonalDistances[ix2] = diagonalDistances[j];
          }

          numberOfRectangles += 2 * counter;
        } //--------------------------------------------------------------
        //                  Update
        //--------------------------------------------------------------


        bestCurrentValue = xMinValue(functionValues);
        choiceLimit = epsilon * Math.abs(bestCurrentValue) > 1e-8 ? epsilon * Math.abs(bestCurrentValue) : 1e-8;
        smallerDistance = getMinIndex(functionValues, diagonalDistances, choiceLimit, bestCurrentValue);
        differentDistances = Array.from(new Set(diagonalDistances));
        differentDistances = differentDistances.sort((a, b) => a - b);
        smallerValuesByDistance = [];

        for (let i = 0; i < differentDistances.length; i++) {
          let minIndex;
          let minValue = Number.POSITIVE_INFINITY;

          for (let k = 0; k < diagonalDistances.length; k++) {
            if (diagonalDistances[k] === differentDistances[i]) {
              if (functionValues[k] < minValue) {
                minValue = functionValues[k];
                minIndex = k;
              }
            }
          }

          smallerValuesByDistance.push(functionValues[minIndex]);
        }

        for (let j = 0; j < functionValues.length; j++) {
          if (functionValues[j] === bestCurrentValue) {
            let temp = [];

            for (let i = 0; i < lowerBoundaries.length; i++) {
              temp.push(lowerBoundaries[i] + unitaryCoordinates[j][i] * diffBorders[i]);
            }
          }
        }

        iteration += 1;
      } //--------------------------------------------------------------
      //                  Saving results
      //--------------------------------------------------------------


      let result = {};
      result.minFunctionValue = bestCurrentValue;
      result.iterations = iteration;
      let originalCoordinates = [];

      for (let j = 0; j < numberOfRectangles + 1; j++) {
        let pair = [];

        for (let i = 0; i < lowerBoundaries.length; i++) {
          pair.push(lowerBoundaries[i] + unitaryCoordinates[j][i] * diffBorders[i]);
        }

        originalCoordinates.push(pair);
      }

      result.finalState = {
        numberOfRectangles,
        totalIterations: totalIterations += iterations,
        originalCoordinates,
        middlePoint,
        fCalls,
        smallerDistance,
        edgeSizes,
        diagonalDistances,
        functionValues,
        differentDistances,
        smallerValuesByDistance,
        choiceLimit
      };
      let minimizer = [];

      for (let i = 0; i < functionValues.length; i++) {
        if (functionValues[i] === bestCurrentValue) {
          minimizer.push(originalCoordinates[i]);
        }
      }

      result.optima = minimizer;
      return result;
    }

    function getMinIndex(functionValues, diagonalDistances, choiceLimit, bestCurrentValue) {
      let item = [];

      for (let i = 0; i < functionValues.length; i++) {
        item[i] = Math.abs(functionValues[i] - (bestCurrentValue + choiceLimit)) / diagonalDistances[i];
      }

      const min = xMinValue(item);
      let result = item.findIndex(x => x === min);
      return result;
    }

    function directOptimization(data, sumOfShapes, options) {
      const {
        minValues,
        maxValues,
        directOptions = {}
      } = options;
      const objectiveFunction = getObjectiveFunction(data, sumOfShapes);
      const result = direct(objectiveFunction, minValues, maxValues, directOptions);
      const {
        optima
      } = result;
      return {
        error: result.minFunctionValue,
        iterations: result.iterations,
        parameterValues: optima[0]
      };
    }

    function getObjectiveFunction(data, sumOfShapes) {
      const {
        x,
        y
      } = data;
      const nbPoints = x.length;
      return parameters => {
        const fct = sumOfShapes(parameters);
        let error = 0;

        for (let i = 0; i < nbPoints; i++) {
          error += Math.pow(y[i] - fct(x[i]), 2);
        }

        return error;
      };
    }

    const defaultParameters = {
      delta: {
        init: data => data.signal.delta,
        min: data => data.signal.delta - data.shape.fwhm * 2,
        max: data => data.signal.delta + data.shape.fwhm * 2,
        gradientDifference: () => 2e-3
      },
      intensity: {
        init: data => data.signal.intensity || 1,
        min: () => 0,
        max: () => 1.5,
        gradientDifference: () => 1e-3
      },
      fwhm: {
        init: data => data.shape.fwhm,
        min: data => data.shape.fwhm * 0.25,
        max: data => data.shape.fwhm * 4,
        gradientDifference: data => data.shape.fwhm * 2e-3
      },
      mu: {
        init: data => data.shape.mu || 0.5,
        min: () => 0,
        max: () => 1,
        gradientDifference: () => 0.01
      },
      coupling: {
        init: data => data.jCoupling.coupling,
        min: data => data.jCoupling.coupling * 0.8,
        max: data => data.jCoupling.coupling * 1.2,
        gradientDifference: () => 0.01
      }
    };

    function signalsToPointXY(signals, options) {
      const {
        frequency,
        maxClusterSize = 1
      } = options;
      const completeSignalSet = addDummySignals(signals);
      const spinSystem = signalsToSpinSystem(completeSignalSet);
      spinSystem.clusters = splitSpinSystem(spinSystem, {
        frequency,
        maxClusterSize
      });
      const pointsXY = simulateXYPeaks(spinSystem, options).filter(point => point.x < 1000);
      const maxIntensity = pointsXY.reduce((max, peak) => peak.y > max ? peak.y : max, Number.MIN_SAFE_INTEGER);

      for (const point of pointsXY) {
        point.y /= maxIntensity;
      }

      return pointsXY;
    }

    const properties = ['init', 'min', 'max', 'gradientDifference'];
    function getInternalSignals(data, signals, minMaxY, options) {
      var _a, _b;

      let index = 0;
      let internalSignals = [];
      const {
        shape: shapeAsOption = {
          kind: 'gaussian'
        },
        baseline: shiftValue = minMaxY.min,
        lineWidth = 1,
        frequency
      } = options;
      const normalizedSignals = normalizeSignals({
        signals,
        data,
        shiftValue,
        frequency,
        range: minMaxY.range
      });

      for (const signal of normalizedSignals) {
        const {
          shape = { ...shapeAsOption
          }
        } = signal;

        if (!shape.fwhm) {
          shape.fwhm = lineWidth;
        }

        shape.fwhm /= frequency;
        const shapeFct = getShape1D(shape);
        const parameters = ['delta', 'intensity', ...shapeFct.getParameters()];
        const propertiesValues = {
          min: [],
          max: [],
          init: [],
          gradientDifference: []
        };

        for (const parameter of parameters) {
          for (const property of properties) {
            propertiesValues[property].push(getPropertyValue({
              signal,
              frequency,
              parameter,
              property,
              minMaxY,
              shapeFct
            }));
          }
        }

        for (const jCoupling of signal.js || []) {
          for (const property of properties) {
            const parameter = 'coupling';
            let generalParameterValue = (_b = (_a = options === null || options === void 0 ? void 0 : options.parameters) === null || _a === void 0 ? void 0 : _a[parameter]) === null || _b === void 0 ? void 0 : _b[property];

            if (generalParameterValue) {
              if (typeof generalParameterValue === 'number') {
                propertiesValues[property].push(getNormalizedValue(generalParameterValue, parameter, property, minMaxY, frequency, options.baseline));
              } else {
                let value = generalParameterValue({
                  jCoupling
                });
                propertiesValues[property].push(getNormalizedValue(value, parameter, property, minMaxY, frequency, options.baseline));
              }
            }

            if (!defaultParameters[parameter]) {
              throw new Error(`No default parameter for ${parameter}`);
            }

            const defaultParameterValues = defaultParameters[parameter][property];
            propertiesValues[property].push(defaultParameterValues({
              jCoupling
            }));
          }
        }

        const fromIndex = index;
        const toIndex = fromIndex + parameters.length - 1;
        const fromIndexCoupling = toIndex + 1;
        const toIndexCoupling = fromIndexCoupling + signal.js.length - 1;
        index += toIndexCoupling - fromIndex + 1;
        internalSignals.push({
          shape: shape,
          shapeFct,
          signal,
          parameters,
          propertiesValues,
          fromIndex,
          toIndex,
          fromIndexCoupling,
          toIndexCoupling
        });
      }

      return internalSignals;
    }

    function normalizeSignals(options) {
      const {
        signals,
        data,
        frequency,
        shiftValue,
        range
      } = options;

      const getMaxIntensity = signal => {
        const peaks = signalsToPointXY([signal], {
          frequency,
          maxClusterSize: 1
        });
        const biggestPeak = peaks.reduce((biggest, peak) => peak.y > biggest.y ? peak : biggest, peaks[0]);
        const {
          y: maxIntensity
        } = xyFindClosestPoint(data, biggestPeak.x);
        return maxIntensity;
      };

      return signals.map(signal => {
        const {
          intensity = getMaxIntensity(signal)
        } = signal;
        return { ...signal,
          js: signal.js || [],
          intensity: (intensity - shiftValue) / range
        };
      });
    }

    function getPropertyValue(options) {
      var _a, _b, _c, _d;

      const {
        signal,
        frequency,
        parameter,
        property,
        minMaxY,
        shapeFct
      } = options; // check if the property is specified in the signal

      let propertyValue = (_b = (_a = signal === null || signal === void 0 ? void 0 : signal.parameters) === null || _a === void 0 ? void 0 : _a[parameter]) === null || _b === void 0 ? void 0 : _b[property];

      if (propertyValue) {
        return getNormalizedValue(propertyValue, parameter, property, minMaxY, frequency, options.baseline);
      } // check if there are some global option, it could be a number or a callback


      let generalParameterValue = (_d = (_c = options === null || options === void 0 ? void 0 : options.parameters) === null || _c === void 0 ? void 0 : _c[parameter]) === null || _d === void 0 ? void 0 : _d[property];

      if (generalParameterValue) {
        if (typeof generalParameterValue === 'number') {
          return getNormalizedValue(generalParameterValue, parameter, property, minMaxY, frequency, options.baseline);
        } else {
          let value = generalParameterValue(signal);
          return getNormalizedValue(value, parameter, property, minMaxY, frequency, options.baseline);
        }
      } // we just need to take the default parameters


      if (!defaultParameters[parameter]) {
        throw new Error(`No default parameter for ${parameter}`);
      }

      const defaultParameterValues = defaultParameters[parameter][property];
      return defaultParameterValues({
        signal,
        shape: shapeFct
      });
    }

    function getNormalizedValue(value, parameter, property, minMaxY, frequency, baseline) {
      if (parameter === 'intensity') {
        if (property === 'gradientDifference') {
          return value;
        } else {
          return baseline !== undefined ? (value - baseline) / minMaxY.range : (value - minMaxY.min) / minMaxY.range;
        }
      } else if (parameter === 'fwhm') {
        return value / frequency;
      }

      return value;
    }

    const defaultSimulationOptions = {
      maxClusterSize: 1
    };
    function getSumOfShapes(internalSignals, options) {
      const simulationOptions = { ...defaultSimulationOptions,
        ...options
      };
      return function sumOfShapes(parameters) {
        const peaks = [];

        for (const internalSignal of internalSignals) {
          const delta = parameters[internalSignal.fromIndex];
          const intensity = parameters[internalSignal.fromIndex + 1];

          for (let i = 2; i < internalSignal.parameters.length; i++) {
            //@ts-expect-error Not simply to solve the issue
            internalSignal.shapeFct[internalSignal.parameters[i]] = parameters[internalSignal.fromIndex + i];
          }

          const couplings = internalSignal.signal.js;

          for (let i = 0; i < couplings.length; i++) {
            couplings[i].coupling = parameters[internalSignal.fromIndexCoupling + i];
          }

          const currentPeaks = signalsToPointXY([{
            delta,
            js: couplings
          }], simulationOptions);
          peaks.push(...currentPeaks.map(peak => {
            return {
              intensity,
              shape: internalSignal.shapeFct,
              ...peak
            };
          }));
        }

        return currentX => {
          let totalY = 0;

          for (let peak of peaks) {
            const {
              x,
              y,
              intensity,
              shape
            } = peak;
            totalY += y * intensity * shape.fct(currentX - x);
          }

          return totalY;
        };
      };
    }

    const defaultLMOptimizationOptions = {
      damping: 1.5,
      maxIterations: 100,
      errorTolerance: 1e-8
    };
    const defaultDirectOptimizationOptions = {
      iterations: 25
    };
    function optimizeSignals(data, signals, options) {
      const {
        optimization = {},
        simulation: simulationOptions,
        ...restOptions
      } = options;
      let temp = xMinMaxValues(data.y);
      const minMaxY = { ...temp,
        range: temp.max - temp.min
      };
      const internalSignals = getInternalSignals(data, signals, minMaxY, {
        frequency: simulationOptions.frequency,
        ...restOptions
      });
      const {
        baseline: shiftValue = minMaxY.min
      } = options;
      let normalizedY = new Float64Array(data.y.length);

      for (let i = 0; i < data.y.length; i++) {
        normalizedY[i] = (data.y[i] - shiftValue) / minMaxY.range;
      }

      const nbParams = internalSignals[internalSignals.length - 1].toIndexCoupling + 1;
      const minValues = new Float64Array(nbParams);
      const maxValues = new Float64Array(nbParams);
      const initialValues = new Float64Array(nbParams);
      const gradientDifferences = new Float64Array(nbParams);
      let index = 0;

      for (const internalSignal of internalSignals) {
        for (let i = 0; i < internalSignal.parameters.length; i++) {
          minValues[index] = internalSignal.propertiesValues.min[i];
          maxValues[index] = internalSignal.propertiesValues.max[i];
          initialValues[index] = internalSignal.propertiesValues.init[i];
          gradientDifferences[index++] = internalSignal.propertiesValues.gradientDifference[i];
        }

        for (let i = internalSignal.parameters.length; i < internalSignal.parameters.length + internalSignal.signal.js.length; i++) {
          minValues[index] = internalSignal.propertiesValues.min[i];
          maxValues[index] = internalSignal.propertiesValues.max[i];
          initialValues[index] = internalSignal.propertiesValues.init[i];
          gradientDifferences[index++] = internalSignal.propertiesValues.gradientDifference[i];
        }
      }

      const sumOfShapes = getSumOfShapes(internalSignals, simulationOptions);
      const {
        kind,
        options: optimizationOptions
      } = optimization;
      const [algorithm, defaultOptimizationOptions] = kind === 'direct' ? [directOptimization, defaultDirectOptimizationOptions] : [levenbergMarquardt, defaultLMOptimizationOptions];
      let fitted = algorithm({
        x: data.x,
        y: normalizedY
      }, sumOfShapes, {
        minValues,
        maxValues,
        initialValues,
        gradientDifference: gradientDifferences,
        ...defaultOptimizationOptions,
        ...optimizationOptions
      });
      const fittedValues = fitted.parameterValues;
      const newSignals = [];

      for (const internalSignal of internalSignals) {
        const {
          fromIndexCoupling
        } = internalSignal;
        const js = internalSignal.signal.js.map((jCoupling, i) => {
          jCoupling.coupling = fittedValues[fromIndexCoupling + i];
          return jCoupling;
        });
        const delta = fittedValues[internalSignal.fromIndex];
        const pointXYs = signalsToPointXY([{
          delta,
          js
        }], simulationOptions);
        const intensity = fittedValues[internalSignal.fromIndex + 1] * minMaxY.range + shiftValue;
        const newPeaks = [];

        for (const {
          x,
          y
        } of pointXYs) {
          const peak = {
            id: v4(),
            x,
            y: intensity * y,
            width: 0,
            shape: { ...internalSignal.shape
            }
          };

          for (let i = 2; i < internalSignal.parameters.length; i++) {
            //@ts-expect-error should be fixed once
            peak.shape[internalSignal.parameters[i]] = fittedValues[internalSignal.fromIndex + i];
          }

          peak.shape.fwhm *= simulationOptions.frequency;
          peak.width = getShape1D(peak.shape).fwhmToWidth(peak.shape.fwhm);
          newPeaks.push(peak);
        }

        newSignals.push({
          delta,
          js,
          shape: { ...newPeaks[0].shape
          },
          intensity,
          peaks: newPeaks
        });
      }

      return newSignals;
    }

    function splitParenthesis(part) {
      const match = / *(?<before>[^(]*?) *\( *(?<inside>.*?) *\) *(?<after>.*?) */.exec(part);

      if (!match) {
        return {
          before: part,
          inside: '',
          after: ''
        };
      }

      return match.groups;
    }

    function splitPatterns(multiplet) {
      if (/^\s*$/.exec(multiplet)) return [];
      let result = multiplet.match(/ *(quint|hex|sept|hept|oct|nona|non|s|d|t|q|h|o|n) */g);
      if (result) return result.map(entry => entry.trim());
      return [multiplet];
    }

    function resurrectRange(part) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        nucleus = '1h',
        frequency = 400
      } = options;
      const split = splitParenthesis(part);
      if (!split.before) return;
      const beforeMatch = /.*?(?<from>-?[0-9.]+)-?(?<to>-?[0-9.]*).*/.exec(split.before);
      if (!beforeMatch || !beforeMatch.groups) return;
      const isARange = beforeMatch.groups.to !== '';
      const from = Number(beforeMatch.groups.from);
      const to = isARange ? Number(beforeMatch.groups.to) : from;
      const insideParts = split.inside.split(/ *, */);
      let signal = {
        delta: NaN,
        js: []
      };
      let range = {
        from,
        to,
        signals: [signal]
      };
      const integrationParts = insideParts.filter(part => part.match(/^[0-9]+H$/));

      if (integrationParts.length === 1) {
        range.integration = Number(integrationParts[0].replace('H', ''));
      }

      const multiplicityParts = insideParts.filter(part => part.match(/^[a-zA-Z]+$/));

      if (multiplicityParts.length === 1) {
        const multiplicity = multiplicityParts[0];

        if (multiplicity === 'm') {
          if (isARange) {
            // a real range
            signal.delta = (from + to) / 2;
            signal.multiplicity = multiplicity;
          } else {
            // a complex signal
            signal.delta = from;
            signal.multiplicity = multiplicity;
          }
        } else if (!isARange) {
          // a complex signal
          signal.delta = from;
          signal.multiplicity = multiplicity;
        }
      }

      const jCouplings = insideParts.filter(part => part.match(/(Hz|J|^[0-9.]+$)/)).map(jCoupling => Number(jCoupling.replace(/[^0-9.]/g, '')));
      const multiplicities = splitPatterns(signal.multiplicity || '');

      if (multiplicities.length === jCouplings.length) {
        for (let i = 0; i < multiplicities.length; i++) {
          if (!signal.js) {
            throw new Error('signal has not js');
          }

          signal.js.push({
            coupling: jCouplings[i],
            multiplicity: multiplicities[i]
          });
        }
      }

      if (range.from === range.to) {
        range = { ...range,
          ...rangeFromSignal(signal, {
            nucleus,
            frequency
          })
        };
      }

      return range;
    }

    function resurrect(acsString) {
      const data = {
        experiment: {},
        ranges: [],
        acsString,
        normalized: acsString.replace(/[\r\n\t]/g, ' ').replace(/[;:]/g, ',').replace(/\}/g, ')').replace(/\{/g, '(').replace(/[\u2011\u2012\u2013\u2014\u2015\u2212]/g, '-')
      };
      createParts(data);
      parseParts(data);
      return data;
    }

    function parseParts(data) {
      for (const part of data.parts) {
        if (part.toLowerCase().includes('nmr')) {
          processExperiment(data, part);
        } else {
          const {
            frequency,
            nucleus
          } = data.experiment;
          const range = resurrectRange(part, {
            frequency,
            nucleus
          });
          if (range) data.ranges.push(range);
        }
      }
    }

    function processExperiment(data, part) {
      const split = splitParenthesis(part);
      const before = split.before.replace(/[ -]*nmr[ -]*/i, '').replace(/[ -]/g, '');

      if (/^[0-9]+[A-Z][a-z]?$/.exec(before)) {
        // 36Cl, 1H, 13C, ...
        data.experiment.nucleus = before;
      }

      if (/^[A-Z][a-z]?[0-9]+$/.exec(before)) {
        // Cl35, H1, C13, ...
        data.experiment.nucleus = before.replace(/^([A-Z][a-z]?)([0-9]+)$/, '$2$1');
      }

      if (split.inside) {
        // some frequency and solvent ???
        const insideParts = split.inside.split(/[,]/);
        const frequencyParts = insideParts.filter(part => /[0-9]{2}/.exec(part));

        if (frequencyParts.length) {
          const frequency = frequencyParts[0].replace(/[^0-9]/g, '');
          if (frequency.length > 1) data.experiment.frequency = Number(frequency);
        }

        const solventParts = insideParts.filter(part => !part.match(/[0-9]{2}/));

        if (solventParts.length) {
          data.experiment.solvent = solventParts[0];
        }
      }
    }

    function createParts(data) {
      const parts = data.normalized.split(/\)(?![^()]*\))/).map(part => part.replace(/^\s*(.*?)\s*$/, '$1')).filter(part => part).map(part => `${part})`).map(part => part.split(/[,;](?![^()]*\))/)).flat().map(part => part.replace(/^\s*(.*?)\s*$/, '$1')).filter(part => part);
      data.parts = parts;
    }

    function convertWidthToHz(peaks, options) {
      return convertWidth(peaks, { ...options,
        convertTo: 'hz'
      });
    }

    function xyAutoPeaksPicking(data, options) {
      const {
        from,
        to,
        frequency,
        noiseLevel,
        thresholdFactor = 3,
        minMaxRatio = 0.05,
        broadRatio = 0.00025,
        useSanPlot = false,
        smoothY = true,
        optimize = false,
        factorLimits = 4,
        realTopDetection = true,
        shape = {
          kind: 'gaussian'
        },
        optimization = {
          kind: 'lm'
        },
        broadWidth = 0.25,
        sgOptions = {},
        direction = 'positive'
      } = options;
      const {
        windowSize = 9,
        polynomial = 3
      } = sgOptions;
      if (data.x.length < windowSize) return [];

      if (from !== undefined && to !== undefined) {
        data = xyExtract(data, {
          zones: [{
            from,
            to
          }]
        });
      }

      const cutOff = getCutOff(data.y, {
        noiseLevel,
        useSanPlot,
        thresholdFactor
      });
      let getPeakOptions = {
        shape,
        frequency,
        broadWidth,
        optimize,
        factorLimits,
        maxCriteria: true,
        sgOptions: {
          windowSize,
          polynomial
        },
        minMaxRatio,
        broadRatio,
        noiseLevel: cutOff.positive,
        smoothY,
        optimization,
        realTopDetection
      };

      switch (direction) {
        case 'positive':
          {
            return getPeakList(data, getPeakOptions);
          }

        case 'negative':
          {
            return getNegativePeaks(data, cutOff, getPeakOptions);
          }

        case 'both':
          {
            return [...getPeakList(data, getPeakOptions), ...getNegativePeaks(data, cutOff, getPeakOptions)];
          }

        default:
          {
            const unHandled = direction; // eslint-disable-next-line @typescript-eslint/restrict-template-expressions

            throw Error(`Unknown distribution ${unHandled}`);
          }
      }
    }

    function getNegativePeaks(data, cutOff, getPeakOptions) {
      getPeakOptions.noiseLevel = cutOff.negative;
      getPeakOptions.maxCriteria = false;
      return getPeakList(data, getPeakOptions);
    }

    function getPeakList(data, options) {
      const {
        shape,
        frequency,
        broadWidth,
        optimize,
        maxCriteria,
        factorLimits,
        sgOptions,
        minMaxRatio,
        broadRatio,
        noiseLevel,
        smoothY,
        optimization,
        realTopDetection
      } = options;
      const peaks = gsd(data, {
        sgOptions,
        maxCriteria,
        minMaxRatio,
        noiseLevel,
        smoothY,
        realTopDetection
      });
      const peakList = setShape(peaks, {
        output: peaks,
        shape
      });
      const newPeaks = broadWidth ? joinBroadPeaks(peakList, {
        broadRatio,
        broadWidth,
        shape,
        optimization
      }).map(toNMRPeak1DStructure) : peakList.map(toNMRPeak1DStructure);
      return convertWidthToHz(optimize ? optimizePeaks(data, newPeaks, {
        shape,
        factorLimits,
        optimization
      }).map(toNMRPeak1DStructure) : newPeaks, {
        frequency
      });
    }

    function getCutOff(data, options) {
      const {
        noiseLevel,
        useSanPlot,
        thresholdFactor
      } = options;

      const formatResult = noiseLevel => typeof noiseLevel === 'number' ? {
        positive: noiseLevel,
        negative: -noiseLevel
      } : noiseLevel;

      if (noiseLevel) {
        return formatResult(noiseLevel);
      } else {
        return useSanPlot ? xNoiseSanPlot(data, {
          factorStd: thresholdFactor
        }) : formatResult(xAbsoluteMedian(data) * thresholdFactor);
      }
    }

    function toNMRPeak1DStructure(peak) {
      const {
        id,
        shape,
        x,
        y,
        width
      } = peak;
      return {
        id,
        x,
        y,
        width,
        shape
      };
    }

    function joinRanges(ranges) {
      ranges.sort((a, b) => a.from - b.from);

      for (let i = 0; i < ranges.length - 1; i++) {
        const currentRange = ranges[i];
        const nextRange = ranges[i + 1];

        if (currentRange.to > nextRange.from) {
          currentRange.id = v4();
          currentRange.to = Math.max(nextRange.to, currentRange.to);

          if (currentRange.signals && nextRange.signals) {
            currentRange.signals = currentRange.signals.concat(nextRange.signals);
          }

          if (currentRange.integration !== undefined) {
            currentRange.integration += nextRange.integration || 0;
          }

          ranges.splice(i + 1, 1);
          i--;
        }
      }

      return ranges;
    }

    /*
     * This library implements the J analyser described by Cobas et al in the paper:
     * A two-stage approach to automatic determination of 1H NMR coupling constants
     */
    const patterns = ['s', 'd', 't', 'q', 'quint', 'h', 'sept', 'o', 'n'];
    let symRatio = 1.5;
    let maxErrorIter1 = 2.5; // Hz

    let maxErrorIter2 = 1; // Hz

    let jAxisKeys = {
      jAxis: 'x',
      intensity: 'intensity'
    };

    function checkSignalForCompilePattern(signal) {
      if (!('symRank' in signal)) {
        throw new Error('Internal error, symRank was not calculated');
      }

      if (!('mask' in signal)) {
        throw new Error('Internal Error, mask was not added');
      }
    }

    var jAnalyzer = {
      /**
       * The compilation process implements at the first stage a normalization procedure described by Golotvin et al.
       * embedding in peak-component-counting method described by Hoyes et al.
       * @param {object} signal
       * @private
       */
      compilePattern: function (inputSignal) {
        let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        let {
          jAxisKey = jAxisKeys
        } = options; // checkForPeaks(inputSignal);
        // const signal = JSON.parse(JSON.stringify(inputSignal));
        // 1.1 symmetrize
        // It will add a set of peaks(signal.peaksComp) to the signal that will be used during
        // the compilation process. The unit of those peaks will be in Hz

        const signal = symmetrizeChoiseBest(inputSignal, {
          maxError: maxErrorIter1,
          iteration: 1,
          jAxisKey
        });
        signal.multiplicity = 'm';
        signal.asymmetric = true; //asserts the signal has all needed

        checkSignalForCompilePattern(signal); // Is the signal symmetric?

        if (signal.symRank >= 0.95 && signal.peaksComp.length < 32) {
          signal.asymmetric = false;
          let P1, n2, maxFlagged;
          let k = 1;
          let jCouplings = []; // Loop over the possible number of coupling contributing to the multiplet

          for (let n = 0; n < 9; n++) {
            // 1.2 Normalize. It makes a deep copy of the peaks before to modify them.
            let peaks = normalize(signal, n);
            let validPattern = false; // It will change to true, when we find the good patter
            // Lets check if the signal could be a singulet.

            if (peaks.length === 1 && n === 0) {
              validPattern = true;
            } else if (peaks.length <= 1) {
              continue;
            } // 1.3 Establish a range for the Heights Hi [peaks.intensity*0.85,peaks.intensity*1.15];


            let ranges = getRanges(peaks);
            n2 = Math.pow(2, n); // 1.4 Find a combination of integer heights Hi, one from each Si, that sums to 2^n.

            let heights = null;
            let counter = 1;

            while (!validPattern && (heights = getNextCombination(ranges, n2)) !== null && counter < 400) {
              // 2.1 Number the components of the multiplet consecutively from 1 to 2n,
              // starting at peak 1
              let numbering = new Array(heights.length);
              k = 1;

              for (let i = 0; i < heights.length; i++) {
                numbering[i] = new Array(heights[i]);

                for (let j = 0; j < heights[i]; j++) {
                  numbering[i][j] = k++;
                }
              }

              jCouplings = []; // The array to store the detected j-coupling
              // 2.2 Set j = 1; J1 = P2 - P1. Flag components 1 and 2 as accounted for.

              let j = 1;
              jCouplings.push(peaks[1].x - peaks[0].x);
              P1 = peaks[0].x;
              numbering[0].splice(0, 1); // Flagged

              numbering[1].splice(0, 1); // Flagged

              k = 1;
              let nFlagged = 2;
              maxFlagged = Math.pow(2, n) - 1;

              while (jCouplings.length < n && nFlagged < maxFlagged && k < peaks.length) {
                counter += 1; // 4.1. Increment j. Set k to the number of the first unflagged component.

                j++;

                while (k < peaks.length && numbering[k].length === 0) {
                  k++;
                }

                if (k < peaks.length) {
                  // 4.2 Jj = Pk - P1.
                  jCouplings.push(peaks[k].x - peaks[0].x); // Flag component k and, for each sum of the...

                  numbering[k].splice(0, 1); // Flageed

                  nFlagged++; // Flag the other components of the multiplet

                  for (let u = 2; u <= j; u++) {
                    let jSum = 0;

                    for (let i = 0; i < u; i++) {
                      jSum += jCouplings[i];
                    }

                    for (let i = 1; i < numbering.length; i++) {
                      // Maybe 0.25 Hz is too much?
                      if (Math.abs(peaks[i].x - (P1 + jSum)) < 0.25) {
                        numbering[i].splice(0, 1); // Flageed

                        nFlagged++;
                        break;
                      }
                    }
                  }
                }
              } // Calculate the ideal patter by using the extracted j-couplings


              let pattern = idealPattern(jCouplings); // Compare the ideal pattern with the proposed intensities.
              // All the intensities have to match to accept the multiplet

              validPattern = true;

              for (let i = 0; i < pattern.length; i++) {
                if (pattern[i].intensity !== heights[i]) {
                  validPattern = false;
                }
              }
            } // If we found a valid pattern we should inform about the pattern.


            if (validPattern) {
              updateSignal(signal, jCouplings);
            }
          }
        } // Before to return, change the units of peaksComp from Hz to PPM again


        for (let peakComp of signal.peaksComp) {
          peakComp.x /= signal.observe;
          peakComp.width *= signal.observe;
        }

        return signal;
      }
    };
    /**
     * @private
     * update the signal
     * @param {*} signal
     * @param {*} jCouplings
     */

    function updateSignal(signal, jCouplings) {
      // Update the limits of the signal
      let peaks = signal.peaksComp; // Always in Hz

      let nbPeaks = peaks.length;
      signal.startX = peaks[0].x / signal.observe - peaks[0].width;
      signal.stopX = peaks[nbPeaks - 1].x / signal.observe + peaks[nbPeaks - 1].width;
      signal.integralData.from = peaks[0].x / signal.observe - peaks[0].width * 3;
      signal.integralData.to = peaks[nbPeaks - 1].x / signal.observe + peaks[nbPeaks - 1].width * 3; // Compile the pattern and format the constant couplings

      signal.maskPattern = signal.mask2;
      signal.multiplicity = abstractPattern(signal, jCouplings);
      signal.pattern = signal.multiplicity; // Our library depends on this parameter, but it is old
    }
    /**
     * Returns the multiplet in the compact format
     * @param {object} signal
     * @param {object} jCouplings
     * @return {String}
     * @private
     */


    function abstractPattern(signal, jCouplings) {
      let tol = 0.05;
      let pattern = '';
      let cont = 1;
      let newNmrJs = [];

      if (jCouplings && jCouplings.length > 0) {
        jCouplings.sort((a, b) => {
          return b - a;
        });

        for (let i = 0; i < jCouplings.length - 1; i++) {
          if (Math.abs(jCouplings[i] - jCouplings[i + 1]) < tol) {
            cont++;
          } else {
            newNmrJs.push({
              coupling: Math.abs(jCouplings[i]),
              multiplicity: patterns[cont]
            });
            pattern += patterns[cont];
            cont = 1;
          }
        }

        let index = jCouplings.length - 1;
        newNmrJs.push({
          coupling: Math.abs(jCouplings[index]),
          multiplicity: patterns[cont]
        });
        pattern += patterns[cont];
        signal.nmrJs = newNmrJs;
      } else {
        pattern = 's';

        if (Math.abs(signal.startX - signal.stopX) * signal.observe > 16) {
          pattern = 'br s';
        }
      }

      return pattern;
    }
    /**
     * This function creates an ideal pattern from the given J-couplings
     * @private
     * @param {Array} jCouplings
     * @return {*[]}
     * @private
     */


    function idealPattern(jCouplings) {
      let hsum = Math.pow(2, jCouplings.length);
      let pattern = [{
        x: 0,
        intensity: hsum
      }]; // To split the initial height

      for (const jc of jCouplings) {
        for (let j = pattern.length - 1; j >= 0; j--) {
          pattern.push({
            x: pattern[j].x + jc / 2,
            intensity: pattern[j].intensity / 2
          });
          pattern[j].x = pattern[j].x - jc / 2;
          pattern[j].intensity = pattern[j].intensity / 2;
        }
      } // To sum the heights in the same positions


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

      for (let j = pattern.length - 2; j >= 0; j--) {
        if (Math.abs(pattern[j].x - pattern[j + 1].x) < 0.1) {
          pattern[j].intensity += pattern[j + 1].intensity;
          pattern.splice(j + 1, 1);
        }
      }

      return pattern;
    }
    /**
     * Find a combination of integer heights Hi, one from each Si, that sums to 2n.
     * @param {object} ranges
     * @param {Number} value
     * @return {*}
     * @private
     */


    function getNextCombination(ranges, value) {
      let half = Math.ceil(ranges.values.length * 0.5);
      let lng = ranges.values.length;
      let sum = 0;
      let ok;

      while (sum !== value) {
        // Update the indexes to point at the next possible combination
        ok = false;

        while (!ok) {
          ok = true;
          ranges.currentIndex[ranges.active]++;

          if (ranges.currentIndex[ranges.active] >= ranges.values[ranges.active].length) {
            // In this case, there is no more possible combinations
            if (ranges.active + 1 === half) {
              return null;
            } else {
              // If this happens we need to try the next active peak
              ranges.currentIndex[ranges.active] = 0;
              ok = false;
              ranges.active++;
            }
          } else {
            ranges.active = 0;
          }
        } // Sum the heights for this combination


        sum = 0;

        for (let i = 0; i < half; i++) {
          sum += ranges.values[i][ranges.currentIndex[i]] * 2;
        }

        if (ranges.values.length % 2 !== 0) {
          sum -= ranges.values[half - 1][ranges.currentIndex[half - 1]];
        }
      } // If the sum is equal to the expected value, fill the array to return


      if (sum === value) {
        let heights = new Array(lng);

        for (let i = 0; i < half; i++) {
          heights[i] = ranges.values[i][ranges.currentIndex[i]];
          heights[lng - i - 1] = ranges.values[i][ranges.currentIndex[i]];
        }

        return heights;
      }

      return null;
    }
    /**
     * This function generates the possible values that each peak can contribute
     * to the multiplet.
     * @param {Array} peaks Array of objects with peaks information {intensity}
     * @return {{values: Array, currentIndex: Array, active: number}}
     * @private
     */


    function getRanges(peaks) {
      let ranges = new Array(peaks.length);
      let currentIndex = new Array(peaks.length);
      let min, max;
      ranges[0] = [1];
      ranges[peaks.length - 1] = [1];
      currentIndex[0] = -1;
      currentIndex[peaks.length - 1] = 0;

      for (let i = 1; i < peaks.length - 1; i++) {
        min = Math.round(peaks[i].intensity * 0.85);
        max = Math.round(peaks[i].intensity * 1.15);
        ranges[i] = [];

        for (let j = min; j <= max; j++) {
          ranges[i].push(j);
        }

        currentIndex[i] = 0;
      }

      return {
        values: ranges,
        currentIndex,
        active: 0
      };
    }
    /**
     * Performs a symmetrization of the signal by using different aproximations to the center.
     * It will return the result of the symmetrization that removes less peaks from the signal
     * @param {object} signal
     * @param {Number} maxError
     * @param {Number} iteration
     * @return {*}
     * @private
     */


    function symmetrizeChoiseBest(signal, options) {
      let {
        maxError,
        iteration,
        jAxisKey = jAxisKeys
      } = options; //make a clone of signal

      let newSignal1 = symmetrize(signal, maxError, iteration, jAxisKey);

      if (!newSignal1.peaksComp) {
        throw new Error('internal peaksComp was not created');
      }

      let tmpPeaks = newSignal1.peaksComp;
      let tmpMask = newSignal1.mask;
      let cs = signal.delta;
      signal.delta = (signal.peaks[0].x + signal.peaks[signal.peaks.length - 1].x) / 2;
      let newSignal2 = symmetrize(signal, maxError, iteration, jAxisKey);

      if (!newSignal2.peaksComp) {
        throw new Error('internal peaksComp was not created');
      }

      if (newSignal2.peaksComp.length > tmpPeaks.length) {
        return newSignal2;
      }

      signal.delta = cs;
      signal.peaksComp = tmpPeaks;
      signal.mask = tmpMask;
      return newSignal1;
    }
    /**
     * This function will return a set of symmetric peaks that will
     * be the enter point for the patter compilation process.
     * @param {object} signal
     * @param {Number} maxError
     * @param {Number} iteration
     * @return {Number}
     * @private
     */


    function symmetrize(signalInput, maxError, iteration, key) {
      let {
        jAxis,
        intensity
      } = key;
      const newSignal = JSON.parse(JSON.stringify(signalInput)); // Before to symmetrize we need to keep only the peaks that possibly conforms the multiplete

      let max, min, avg, ratio, avgWidth;
      let peaks = new Array(newSignal.peaks.length); // Make a deep copy of the peaks and convert PPM ot HZ

      for (let i = 0; i < peaks.length; i++) {
        let peak = newSignal.peaks[i];
        peaks[i] = {
          x: peak[jAxis] * newSignal.observe,
          intensity: peak[intensity],
          width: peak.width / newSignal.observe
        };
      } // Join the peaks that are closer than 0.25 Hz


      for (let i = peaks.length - 2; i >= 0; i--) {
        if (Math.abs(peaks[i].x - peaks[i + 1].x) < 0.25) {
          peaks[i].x = peaks[i].x * peaks[i].intensity + peaks[i + 1].x * peaks[i + 1].intensity;
          peaks[i].intensity = peaks[i].intensity + peaks[i + 1].intensity;
          peaks[i].x /= peaks[i].intensity;
          peaks[i].intensity /= 2;
          peaks[i].width += peaks[i + 1].width;
          peaks.splice(i + 1, 1);
        }
      }

      newSignal.peaksComp = peaks;
      let nbPeaks = peaks.length;
      let mask = new Array(nbPeaks);
      newSignal.mask = mask;
      let left = 0;
      let right = peaks.length - 1;
      let cs = newSignal.delta * newSignal.observe;
      let middle = [(peaks[0].x + peaks[nbPeaks - 1].x) / 2, 1];
      maxError = error(Math.abs(cs - middle[0]));
      let heightSum = 0; // We try to symmetrize the extreme peaks. We consider as candidates for symmetricing those which have
      // ratio smaller than 3

      for (let i = 0; i < nbPeaks; i++) {
        mask[i] = true; // heightSum += signal.peaks[i].intensity;

        heightSum += peaks[i].intensity;
      }

      while (left <= right) {
        mask[left] = true;
        mask[right] = true;

        if (left === right) {
          if (nbPeaks > 2 && Math.abs(peaks[left].x - cs) > maxError) {
            mask[left] = false;
          }
        } else {
          max = Math.max(peaks[left].intensity, peaks[right].intensity);
          min = Math.min(peaks[left].intensity, peaks[right].intensity);
          ratio = max / min;

          if (ratio > symRatio) {
            if (peaks[left].intensity === min) {
              mask[left] = false;
              right++;
            } else {
              mask[right] = false;
              left--;
            }
          } else {
            let diffL = Math.abs(peaks[left].x - cs);
            let diffR = Math.abs(peaks[right].x - cs);

            if (Math.abs(diffL - diffR) < maxError) {
              avg = Math.min(peaks[left].intensity, peaks[right].intensity);
              avgWidth = Math.min(peaks[left].width, peaks[right].width);
              peaks[left].intensity = avg;
              peaks[right].intensity = avg;
              peaks[left].width = avgWidth;
              peaks[right].width = avgWidth;
              middle = [middle[0] + (peaks[right].x + peaks[left].x) / 2, middle[1] + 1];
            } else if (Math.max(diffL, diffR) === diffR) {
              mask[right] = false;
              left--;
            } else {
              mask[left] = false;
              right++;
            }
          }
        }

        left++;
        right--; // Only alter cs if it is the first iteration of the sym process.

        if (iteration === 1) {
          cs = chemicalShift(peaks, mask); // There is not more available peaks

          if (isNaN(cs)) {
            newSignal.symRank = 0;
            return newSignal;
          }
        }

        maxError = error(Math.abs(cs - middle[0] / middle[1]));
      } // To remove the weak peaks and recalculate the cs


      for (let i = nbPeaks - 1; i >= 0; i--) {
        if (mask[i] === false) {
          peaks.splice(i, 1);
        }
      }

      cs = chemicalShift(peaks);

      if (isNaN(cs)) {
        newSignal.symRank = 0;
        return newSignal;
      }

      newSignal.delta = cs / newSignal.observe; // Now, the peak should be symmetric in heights, but we need to know if it is symmetric in x

      let symFactor = 0;
      let weight = 0;

      if (peaks.length > 1) {
        for (let i = Math.ceil(peaks.length / 2) - 1; i >= 0; i--) {
          symFactor += (3 + Math.min(Math.abs(peaks[i].x - cs), Math.abs(peaks[peaks.length - 1 - i].x - cs))) / (3 + Math.max(Math.abs(peaks[i].x - cs), Math.abs(peaks[peaks.length - 1 - i].x - cs))) * peaks[i].intensity;
          weight += peaks[i].intensity;
        }

        symFactor /= weight;
      } else if (peaks.length === 1) {
        symFactor = 1;
      }

      let newSumHeights = 0;

      for (const peak of peaks) {
        newSumHeights += peak.intensity;
      }

      symFactor -= (heightSum - newSumHeights) / heightSum * 0.12; // Removed peaks penalty
      // Sometimes we need a second opinion after the first symmetrization.

      if (symFactor > 0.8 && symFactor < 0.97 && iteration < 2) {
        return symmetrize(newSignal, maxErrorIter2, 2, key);
      } else if (peaks.length > 1) {
        // Center the given pattern at cs and symmetrize x
        let dxi;

        for (let i = Math.ceil(peaks.length / 2) - 1; i >= 0; i--) {
          dxi = (peaks[i].x - peaks[peaks.length - 1 - i].x) / 2.0;
          peaks[i].x = cs + dxi;
          peaks[peaks.length - 1 - i].x = cs - dxi;
        }
      }

      newSignal.symRank = symFactor;
      return newSignal;
    }
    /**
     * Error validator
     * @param {Number} value
     * @return {Number}
     * @private
     */


    function error(value) {
      let maxError = value * 2.5;

      if (maxError < 0.75) {
        maxError = 0.75;
      }

      if (maxError > 3) {
        maxError = 3;
      }

      return maxError;
    }
    /**
     * @private
     * 2 stages normalizarion of the peaks heights to Math.pow(2,n).
     * Creates a new mask with the peaks that could contribute to the multiplete
     * @param {object} signal
     * @param {Number} n
     * @return {*}
     */


    function normalize(signal, n) {
      // Perhaps this is slow
      let peaks = JSON.parse(JSON.stringify(signal.peaksComp));
      let norm = 0;
      let norm2 = 0;

      for (let peak of peaks) {
        norm += peak.intensity;
      }

      norm = Math.pow(2, n) / norm;
      signal.mask2 = signal.mask.slice();
      let index = signal.mask2.length - 1;

      for (let i = peaks.length - 1; i >= 0; i--) {
        peaks[i].intensity *= norm;

        while (index >= 0 && !signal.mask2[index]) {
          index--;
        }

        if (peaks[i].intensity < 0.75) {
          peaks.splice(i, 1);
          signal.mask2[index] = false;
        } else {
          norm2 += peaks[i].intensity;
        }

        index--;
      }

      norm2 = Math.pow(2, n) / norm2;

      for (let i = peaks.length - 1; i >= 0; i--) {
        peaks[i].intensity *= norm2;
      }

      return peaks;
    }
    /**
     * @private
     * Calculates the chemical shift as the weighted sum of the peaks
     * @param {Array} peaks
     * @param {Array} mask
     * @return {Number}
     */


    function chemicalShift(peaks) {
      let mask = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
      let sum = 0;
      let cs = 0;
      let area;

      if (mask.length > 0) {
        for (let i = 0; i < peaks.length; i++) {
          if (mask[i]) {
            area = getArea(peaks[i]);
            sum += area;
            cs += area * peaks[i].x;
          }
        }
      } else {
        for (let peak of peaks) {
          area = getArea(peak);
          sum += area;
          cs += area * peak.x;
        }
      }

      return cs / sum;
    }
    /**
     * Return the area of a Lorentzian function
     * @param {object} peak - object with peak information
     * @return {Number}
     * @private
     */


    function getArea(peak) {
      return Math.abs(peak.intensity * peak.width * 1.57); // 1.772453851);
    }

    function checkSignalAfterCompilePattern(signal) {
      // if (!signal.symRank)
      //   throw new Error('Internal error, symRank was not calculated');
      if (!signal.mask) throw new Error('Internal Error, mask was not added');
      if (!signal.mask2) throw new Error('Internal Error, mask2 was not added');

      if (!signal.maskPattern) {
        throw new Error('Internal Error, maskPattern was not added');
      }
    }

    const assignSignal = (peak, frequency, nucleus) => {
      return {
        id: v4(),
        delta: NaN,
        nbPeaks: 1,
        kind: 'signal',
        startX: peak.x - peak.width / frequency,
        stopX: peak.x + peak.width / frequency,
        observe: frequency,
        nucleus,
        integralData: {
          from: peak.x - peak.width * 3 / frequency,
          to: peak.x + peak.width * 3 / frequency,
          value: 0
        },
        peaks: [{
          x: peak.x,
          intensity: peak.y,
          width: peak.width
        }]
      };
    };
    /**
     * This function clustering peaks and calculate the integration value for each range from the peak list returned from extractPeaks function.
     */


    function peaksToRanges(data, peakList) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      let {
        integrationSum = 100,
        joinOverlapRanges = true,
        clean = 0.4,
        compile = true,
        integralType = 'sum',
        frequency = 400,
        frequencyCluster = 16,
        keepPeaks = false,
        nucleus = '1H'
      } = options;
      let signalOptions = {
        integrationSum,
        integralType,
        frequencyCluster,
        frequency,
        nucleus
      };
      if (peakList.length === 0) return [];

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

      let signals = detectSignals(data, peakList, signalOptions);

      if (clean) {
        for (let i = 0; i < signals.length; i++) {
          if (Math.abs(signals[i].integralData.value) < clean) {
            signals.splice(i, 1);
          }
        }
      }

      if (compile) {
        let nHi, sum;

        for (let i = 0; i < signals.length; i++) {
          signals[i] = jAnalyzer.compilePattern(signals[i]);
          let signal = signals[i];

          if (signal.maskPattern && signal.multiplicity !== 'm' && signal.multiplicity !== '') {
            checkSignalAfterCompilePattern(signal); // Create a new signal with the removed peaks

            nHi = 0;
            sum = 0;
            let peaksO = [];

            for (let j = signal.maskPattern.length - 1; j >= 0; j--) {
              sum += computeArea(signal.peaks[j], frequency);

              if (!signal.maskPattern[j]) {
                let peakR = signal.peaks.splice(j, 1)[0];
                peaksO.push({
                  x: peakR.x,
                  y: peakR.intensity,
                  width: peakR.width
                });
                signal.mask.splice(j, 1);
                signal.mask2.splice(j, 1);
                signal.maskPattern.splice(j, 1);
                signal.nbPeaks--;
                nHi += computeArea(peakR, frequency);
              }
            }

            if (peaksO.length > 0) {
              nHi = nHi * signal.integralData.value / sum;
              signal.integralData.value -= nHi;
              let peaks1 = [];

              for (let j = peaksO.length - 1; j >= 0; j--) {
                peaks1.push(peaksO[j]);
              }

              signalOptions.integrationSum = Math.abs(nHi);
              let ranges = detectSignals(data, peaks1, signalOptions);

              for (const range of ranges) {
                signals.push(range);
              }
            }
          }
        } // it was a updateIntegrals function.


        let sumIntegral = 0;
        let sumObserved = 0;

        for (const signal of signals) {
          sumObserved += Math.abs(Math.round(signal.integralData.value));
        }

        if (sumObserved !== integrationSum) {
          sumIntegral = integrationSum / sumObserved;

          for (const signal of signals) {
            signal.integralData.value *= sumIntegral;
          }
        }
      }

      signals.sort((a, b) => {
        return b.delta - a.delta;
      });

      if (clean) {
        for (let i = signals.length - 1; i >= 0; i--) {
          if (Math.abs(signals[i].integralData.value) < clean) {
            signals.splice(i, 1);
          }
        }
      }

      let ranges = [];

      for (let i = 0; i < signals.length; i++) {
        let signal = signals[i];
        const range = {
          id: v4(),
          from: signal.integralData.from,
          to: signal.integralData.to,
          integration: signal.integralData.value
        };
        const signalResult = {
          delta: signal.delta,
          kind: signal.kind || 'signal',
          multiplicity: signal.multiplicity,
          integration: signal.integralData.value
        };

        if (keepPeaks) {
          signalResult.peaks = signal.peaks.map(peak => {
            const newResult = {
              y: peak.intensity,
              ...peak
            };
            delete newResult.intensity;
            return newResult;
          });
        }

        if (signal.nmrJs) {
          signalResult.js = signal.nmrJs;
        }

        range.signals = [signalResult];
        ranges[i] = range;
      }

      if (joinOverlapRanges) ranges = joinRanges(ranges);
      return ranges;
    }
    /**
     * Extract the signals from the peakList and the given spectrum.
     * @param {object} data - spectra data
     * @param {array} peakList - nmr signals
     * @param {object} [options = {}]
     * @param {number} [options.integrationSum='100'] - Number of hydrogens or some number to normalize the integration data, If it's zero return the absolute integration value
     * @param {string} [options.integralType='sum'] - option to chose between approx area with peaks or the sum of the points of given range
     * @param {number} [options.frequencyCluster=16] - distance limit to clustering the peaks.
     * range = frequencyCluster / observeFrequency -> Peaks withing this range are considered to belongs to the same signal1D
     * @param {string} [options.nucleus='1H'] - - Nucleus
     * @param {String} [options.frequency = 400] - Observed frequency
     * @return {array} nmr signals
     * @private
     */

    function detectSignals(data, peakList) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      let {
        integrationSum = 100,
        integralType = 'sum',
        frequencyCluster = 16,
        frequency = 400,
        nucleus = '1H'
      } = options;
      let signal1D = assignSignal(peakList[0], frequency, nucleus);
      let peaks;
      let signals = [];
      let prevPeak = {
        x: Number.MIN_SAFE_INTEGER
      };
      let spectrumIntegral = 0;
      frequencyCluster /= frequency;

      for (const peak of peakList) {
        if (Math.abs(peak.x - prevPeak.x) > frequencyCluster) {
          signal1D = assignSignal(peak, frequency, nucleus);
          if (peak.kind) signal1D.kind = peak.kind;
          signals.push(signal1D);
        } else {
          let tmp = peak.x + peak.width / frequency;
          signal1D.stopX = Math.max(signal1D.stopX, tmp);
          signal1D.startX = Math.min(signal1D.startX, tmp);
          signal1D.nbPeaks++;
          signal1D.peaks.push({
            x: peak.x,
            intensity: peak.y,
            width: peak.width
          });
          signal1D.integralData.from = Math.min(signal1D.integralData.from, peak.x - peak.width * 3 / frequency);
          signal1D.integralData.to = Math.max(signal1D.integralData.to, peak.x + peak.width * 3 / frequency);
          if (peak.kind) signal1D.kind = peak.kind;
        }

        prevPeak = peak;
      }

      for (let signal of signals) {
        peaks = signal.peaks;
        let integration = signal.integralData;
        let chemicalShift = 0;
        let integralPeaks = 0;

        for (const peak of peaks) {
          let area = computeArea(peak, frequency);
          chemicalShift += peak.x * area;
          integralPeaks += area;
        }

        signal.delta = chemicalShift / integralPeaks;

        if (integralType === 'sum') {
          integration.value = xyIntegration(data, {
            from: integration.from,
            to: integration.to
          });
        } else {
          integration.value = integralPeaks;
        }

        spectrumIntegral += integration.value;
      }

      if (integrationSum > 0) {
        let integralFactor = integrationSum / spectrumIntegral;

        for (let signal of signals) {
          let integration = signal.integralData;
          integration.value *= integralFactor;
        }
      }

      return signals;
    }
    /**
     * Return the area of a Lorentzian function
     * @private
     */

    function computeArea(peak, frequency) {
      return Math.abs(peak.intensity * peak.width / frequency * 1.57); // todo add an option with this value: 1.772453851
    }

    /**
     * Detect peaks, optimize parameters and compile multiplicity if required.
     */

    function xyAutoRangesPicking(data, options) {
      let peaks = xyAutoPeaksPicking(data, options.peakPicking);
      peaks = peaksFilterImpurities(peaks, options.impurities);
      return peaksToRanges(data, peaks, options.ranges);
    }

    function xyPeaksOptimization(data, peaks, options) {
      const {
        frequency
      } = options;
      const newPeaks = convertWidthToPPM(peaks, {
        frequency
      });
      const optimizedPeaks = optimizePeaks(data, newPeaks, options);
      const result = convertWidthToHz(optimizedPeaks, {
        frequency,
        output: optimizedPeaks
      });
      return result;
    }

    var src = {};

    var fftlib = {};

    /**
     * Fast Fourier Transform module
     * 1D-FFT/IFFT, 2D-FFT/IFFT (radix-2)
     */

    (function (exports) {
      (function () {
        var FFT;

        {
          FFT = exports; // for CommonJS
        }

        var version = {
          release: '0.3.0',
          date: '2013-03'
        };

        FFT.toString = function () {
          return "version " + version.release + ", released " + version.date;
        }; // core operations


        var _n = 0,
            // order
        _bitrev = null,
            // bit reversal table
        _cstb = null; // sin/cos table

        var core = {
          init: function (n) {
            if (n !== 0 && (n & n - 1) === 0) {
              _n = n;

              core._initArray();

              core._makeBitReversalTable();

              core._makeCosSinTable();
            } else {
              throw new Error("init: radix-2 required");
            }
          },
          // 1D-FFT
          fft1d: function (re, im) {
            core.fft(re, im, 1);
          },
          // 1D-IFFT
          ifft1d: function (re, im) {
            var n = 1 / _n;
            core.fft(re, im, -1);

            for (var i = 0; i < _n; i++) {
              re[i] *= n;
              im[i] *= n;
            }
          },
          // 1D-IFFT
          bt1d: function (re, im) {
            core.fft(re, im, -1);
          },
          // 2D-FFT Not very useful if the number of rows have to be equal to cols
          fft2d: function (re, im) {
            var tre = [],
                tim = [],
                i = 0; // x-axis

            for (var y = 0; y < _n; y++) {
              i = y * _n;

              for (var x1 = 0; x1 < _n; x1++) {
                tre[x1] = re[x1 + i];
                tim[x1] = im[x1 + i];
              }

              core.fft1d(tre, tim);

              for (var x2 = 0; x2 < _n; x2++) {
                re[x2 + i] = tre[x2];
                im[x2 + i] = tim[x2];
              }
            } // y-axis


            for (var x = 0; x < _n; x++) {
              for (var y1 = 0; y1 < _n; y1++) {
                i = x + y1 * _n;
                tre[y1] = re[i];
                tim[y1] = im[i];
              }

              core.fft1d(tre, tim);

              for (var y2 = 0; y2 < _n; y2++) {
                i = x + y2 * _n;
                re[i] = tre[y2];
                im[i] = tim[y2];
              }
            }
          },
          // 2D-IFFT
          ifft2d: function (re, im) {
            var tre = [],
                tim = [],
                i = 0; // x-axis

            for (var y = 0; y < _n; y++) {
              i = y * _n;

              for (var x1 = 0; x1 < _n; x1++) {
                tre[x1] = re[x1 + i];
                tim[x1] = im[x1 + i];
              }

              core.ifft1d(tre, tim);

              for (var x2 = 0; x2 < _n; x2++) {
                re[x2 + i] = tre[x2];
                im[x2 + i] = tim[x2];
              }
            } // y-axis


            for (var x = 0; x < _n; x++) {
              for (var y1 = 0; y1 < _n; y1++) {
                i = x + y1 * _n;
                tre[y1] = re[i];
                tim[y1] = im[i];
              }

              core.ifft1d(tre, tim);

              for (var y2 = 0; y2 < _n; y2++) {
                i = x + y2 * _n;
                re[i] = tre[y2];
                im[i] = tim[y2];
              }
            }
          },
          // core operation of FFT
          fft: function (re, im, inv) {
            var d,
                h,
                ik,
                m,
                tmp,
                wr,
                wi,
                xr,
                xi,
                n4 = _n >> 2; // bit reversal

            for (var l = 0; l < _n; l++) {
              m = _bitrev[l];

              if (l < m) {
                tmp = re[l];
                re[l] = re[m];
                re[m] = tmp;
                tmp = im[l];
                im[l] = im[m];
                im[m] = tmp;
              }
            } // butterfly operation


            for (var k = 1; k < _n; k <<= 1) {
              h = 0;
              d = _n / (k << 1);

              for (var j = 0; j < k; j++) {
                wr = _cstb[h + n4];
                wi = inv * _cstb[h];

                for (var i = j; i < _n; i += k << 1) {
                  ik = i + k;
                  xr = wr * re[ik] + wi * im[ik];
                  xi = wr * im[ik] - wi * re[ik];
                  re[ik] = re[i] - xr;
                  re[i] += xr;
                  im[ik] = im[i] - xi;
                  im[i] += xi;
                }

                h += d;
              }
            }
          },
          // initialize the array (supports TypedArray)
          _initArray: function () {
            if (typeof Uint32Array !== 'undefined') {
              _bitrev = new Uint32Array(_n);
            } else {
              _bitrev = [];
            }

            if (typeof Float64Array !== 'undefined') {
              _cstb = new Float64Array(_n * 1.25);
            } else {
              _cstb = [];
            }
          },
          // zero padding
          _paddingZero: function () {// TODO
          },
          // makes bit reversal table
          _makeBitReversalTable: function () {
            var i = 0,
                j = 0,
                k = 0;
            _bitrev[0] = 0;

            while (++i < _n) {
              k = _n >> 1;

              while (k <= j) {
                j -= k;
                k >>= 1;
              }

              j += k;
              _bitrev[i] = j;
            }
          },
          // makes trigonometiric function table
          _makeCosSinTable: function () {
            var n2 = _n >> 1,
                n4 = _n >> 2,
                n8 = _n >> 3,
                n2p4 = n2 + n4,
                t = Math.sin(Math.PI / _n),
                dc = 2 * t * t,
                ds = Math.sqrt(dc * (2 - dc)),
                c = _cstb[n4] = 1,
                s = _cstb[0] = 0;
            t = 2 * dc;

            for (var i = 1; i < n8; i++) {
              c -= dc;
              dc += t * c;
              s += ds;
              ds -= t * s;
              _cstb[i] = s;
              _cstb[n4 - i] = c;
            }

            if (n8 !== 0) {
              _cstb[n8] = Math.sqrt(0.5);
            }

            for (var j = 0; j < n4; j++) {
              _cstb[n2 - j] = _cstb[j];
            }

            for (var k = 0; k < n2p4; k++) {
              _cstb[k + n2] = -_cstb[k];
            }
          }
        }; // aliases (public APIs)

        var apis = ['init', 'fft1d', 'ifft1d', 'fft2d', 'ifft2d'];

        for (var i = 0; i < apis.length; i++) {
          FFT[apis[i]] = core[apis[i]];
        }

        FFT.bt = core.bt1d;
        FFT.fft = core.fft1d;
        FFT.ifft = core.ifft1d;
        return FFT;
      }).call(commonjsGlobal);
    })(fftlib);

    var FFT = fftlib;
    var FFTUtils$1 = {
      DEBUG: false,

      /**
       * Calculates the inverse of a 2D Fourier transform
       *
       * @param ft
       * @param ftRows
       * @param ftCols
       * @return
       */
      ifft2DArray: function (ft, ftRows, ftCols) {
        var tempTransform = new Array(ftRows * ftCols);
        var nRows = ftRows / 2;
        var nCols = (ftCols - 1) * 2; // reverse transform columns

        FFT.init(nRows);
        var tmpCols = {
          re: new Array(nRows),
          im: new Array(nRows)
        };

        for (var iCol = 0; iCol < ftCols; iCol++) {
          for (var iRow = nRows - 1; iRow >= 0; iRow--) {
            tmpCols.re[iRow] = ft[iRow * 2 * ftCols + iCol];
            tmpCols.im[iRow] = ft[(iRow * 2 + 1) * ftCols + iCol];
          } //Unnormalized inverse transform


          FFT.bt(tmpCols.re, tmpCols.im);

          for (var iRow = nRows - 1; iRow >= 0; iRow--) {
            tempTransform[iRow * 2 * ftCols + iCol] = tmpCols.re[iRow];
            tempTransform[(iRow * 2 + 1) * ftCols + iCol] = tmpCols.im[iRow];
          }
        } // reverse row transform


        var finalTransform = new Array(nRows * nCols);
        FFT.init(nCols);
        var tmpRows = {
          re: new Array(nCols),
          im: new Array(nCols)
        };
        var scale = nCols * nRows;

        for (var iRow = 0; iRow < ftRows; iRow += 2) {
          tmpRows.re[0] = tempTransform[iRow * ftCols];
          tmpRows.im[0] = tempTransform[(iRow + 1) * ftCols];

          for (var iCol = 1; iCol < ftCols; iCol++) {
            tmpRows.re[iCol] = tempTransform[iRow * ftCols + iCol];
            tmpRows.im[iCol] = tempTransform[(iRow + 1) * ftCols + iCol];
            tmpRows.re[nCols - iCol] = tempTransform[iRow * ftCols + iCol];
            tmpRows.im[nCols - iCol] = -tempTransform[(iRow + 1) * ftCols + iCol];
          } //Unnormalized inverse transform


          FFT.bt(tmpRows.re, tmpRows.im);
          var indexB = iRow / 2 * nCols;

          for (var iCol = nCols - 1; iCol >= 0; iCol--) {
            finalTransform[indexB + iCol] = tmpRows.re[iCol] / scale;
          }
        }

        return finalTransform;
      },

      /**
       * Calculates the fourier transform of a matrix of size (nRows,nCols) It is
       * assumed that both nRows and nCols are a power of two
       *
       * On exit the matrix has dimensions (nRows * 2, nCols / 2 + 1) where the
       * even rows contain the real part and the odd rows the imaginary part of the
       * transform
       * @param data
       * @param nRows
       * @param nCols
       * @return
       */
      fft2DArray: function (data, nRows, nCols, opt) {
        Object.assign({}, {
          inplace: true
        });
        var ftCols = nCols / 2 + 1;
        var ftRows = nRows * 2;
        var tempTransform = new Array(ftRows * ftCols);
        FFT.init(nCols); // transform rows

        var tmpRows = {
          re: new Array(nCols),
          im: new Array(nCols)
        };
        var row1 = {
          re: new Array(nCols),
          im: new Array(nCols)
        };
        var row2 = {
          re: new Array(nCols),
          im: new Array(nCols)
        };
        var index, iRow0, iRow1, iRow2, iRow3;

        for (var iRow = 0; iRow < nRows / 2; iRow++) {
          index = iRow * 2 * nCols;
          tmpRows.re = data.slice(index, index + nCols);
          index = (iRow * 2 + 1) * nCols;
          tmpRows.im = data.slice(index, index + nCols);
          FFT.fft1d(tmpRows.re, tmpRows.im);
          this.reconstructTwoRealFFT(tmpRows, row1, row2); //Now lets put back the result into the output array

          iRow0 = iRow * 4 * ftCols;
          iRow1 = (iRow * 4 + 1) * ftCols;
          iRow2 = (iRow * 4 + 2) * ftCols;
          iRow3 = (iRow * 4 + 3) * ftCols;

          for (var k = ftCols - 1; k >= 0; k--) {
            tempTransform[iRow0 + k] = row1.re[k];
            tempTransform[iRow1 + k] = row1.im[k];
            tempTransform[iRow2 + k] = row2.re[k];
            tempTransform[iRow3 + k] = row2.im[k];
          }
        } //console.log(tempTransform);


        row1 = null;
        row2 = null; // transform columns

        var finalTransform = new Array(ftRows * ftCols);
        FFT.init(nRows);
        var tmpCols = {
          re: new Array(nRows),
          im: new Array(nRows)
        };

        for (var iCol = ftCols - 1; iCol >= 0; iCol--) {
          for (var iRow = nRows - 1; iRow >= 0; iRow--) {
            tmpCols.re[iRow] = tempTransform[iRow * 2 * ftCols + iCol];
            tmpCols.im[iRow] = tempTransform[(iRow * 2 + 1) * ftCols + iCol]; //TODO Chech why this happens

            if (isNaN(tmpCols.re[iRow])) {
              tmpCols.re[iRow] = 0;
            }

            if (isNaN(tmpCols.im[iRow])) {
              tmpCols.im[iRow] = 0;
            }
          }

          FFT.fft1d(tmpCols.re, tmpCols.im);

          for (var iRow = nRows - 1; iRow >= 0; iRow--) {
            finalTransform[iRow * 2 * ftCols + iCol] = tmpCols.re[iRow];
            finalTransform[(iRow * 2 + 1) * ftCols + iCol] = tmpCols.im[iRow];
          }
        } //console.log(finalTransform);


        return finalTransform;
      },

      /**
       *
       * @param fourierTransform
       * @param realTransform1
       * @param realTransform2
       *
       * Reconstructs the individual Fourier transforms of two simultaneously
       * transformed series. Based on the Symmetry relationships (the asterisk
       * denotes the complex conjugate)
       *
       * F_{N-n} = F_n^{*} for a purely real f transformed to F
       *
       * G_{N-n} = G_n^{*} for a purely imaginary g transformed to G
       *
       */
      reconstructTwoRealFFT: function (fourierTransform, realTransform1, realTransform2) {
        var length = fourierTransform.re.length; // the components n=0 are trivial

        realTransform1.re[0] = fourierTransform.re[0];
        realTransform1.im[0] = 0.0;
        realTransform2.re[0] = fourierTransform.im[0];
        realTransform2.im[0] = 0.0;
        var rm, rp, im, ip, j;

        for (var i = length / 2; i > 0; i--) {
          j = length - i;
          rm = 0.5 * (fourierTransform.re[i] - fourierTransform.re[j]);
          rp = 0.5 * (fourierTransform.re[i] + fourierTransform.re[j]);
          im = 0.5 * (fourierTransform.im[i] - fourierTransform.im[j]);
          ip = 0.5 * (fourierTransform.im[i] + fourierTransform.im[j]);
          realTransform1.re[i] = rp;
          realTransform1.im[i] = im;
          realTransform1.re[j] = rp;
          realTransform1.im[j] = -im;
          realTransform2.re[i] = ip;
          realTransform2.im[i] = -rm;
          realTransform2.re[j] = ip;
          realTransform2.im[j] = rm;
        }
      },

      /**
       * In place version of convolute 2D
       *
       * @param ftSignal
       * @param ftFilter
       * @param ftRows
       * @param ftCols
       * @return
       */
      convolute2DI: function (ftSignal, ftFilter, ftRows, ftCols) {
        var re, im;

        for (var iRow = 0; iRow < ftRows / 2; iRow++) {
          for (var iCol = 0; iCol < ftCols; iCol++) {
            //
            re = ftSignal[iRow * 2 * ftCols + iCol] * ftFilter[iRow * 2 * ftCols + iCol] - ftSignal[(iRow * 2 + 1) * ftCols + iCol] * ftFilter[(iRow * 2 + 1) * ftCols + iCol];
            im = ftSignal[iRow * 2 * ftCols + iCol] * ftFilter[(iRow * 2 + 1) * ftCols + iCol] + ftSignal[(iRow * 2 + 1) * ftCols + iCol] * ftFilter[iRow * 2 * ftCols + iCol]; //

            ftSignal[iRow * 2 * ftCols + iCol] = re;
            ftSignal[(iRow * 2 + 1) * ftCols + iCol] = im;
          }
        }
      },

      /**
       *
       * @param data
       * @param kernel
       * @param nRows
       * @param nCols
       * @returns {*}
       */
      convolute: function (data, kernel, nRows, nCols, opt) {
        var ftSpectrum = new Array(nCols * nRows);

        for (var i = 0; i < nRows * nCols; i++) {
          ftSpectrum[i] = data[i];
        }

        ftSpectrum = this.fft2DArray(ftSpectrum, nRows, nCols);
        var dimR = kernel.length;
        var dimC = kernel[0].length;
        var ftFilterData = new Array(nCols * nRows);

        for (var i = 0; i < nCols * nRows; i++) {
          ftFilterData[i] = 0;
        }

        var iRow, iCol;
        var shiftR = Math.floor((dimR - 1) / 2);
        var shiftC = Math.floor((dimC - 1) / 2);

        for (var ir = 0; ir < dimR; ir++) {
          iRow = (ir - shiftR + nRows) % nRows;

          for (var ic = 0; ic < dimC; ic++) {
            iCol = (ic - shiftC + nCols) % nCols;
            ftFilterData[iRow * nCols + iCol] = kernel[ir][ic];
          }
        }

        ftFilterData = this.fft2DArray(ftFilterData, nRows, nCols);
        var ftRows = nRows * 2;
        var ftCols = nCols / 2 + 1;
        this.convolute2DI(ftSpectrum, ftFilterData, ftRows, ftCols);
        return this.ifft2DArray(ftSpectrum, ftRows, ftCols);
      },
      toRadix2: function (data, nRows, nCols) {
        var i, j, irow, icol;
        var cols = nCols,
            rows = nRows;

        if (!(nCols !== 0 && (nCols & nCols - 1) === 0)) {
          //Then we have to make a pading to next radix2
          cols = 0;

          while (nCols >> ++cols != 0);

          cols = 1 << cols;
        }

        if (!(nRows !== 0 && (nRows & nRows - 1) === 0)) {
          //Then we have to make a pading to next radix2
          rows = 0;

          while (nRows >> ++rows != 0);

          rows = 1 << rows;
        }

        if (rows == nRows && cols == nCols) //Do nothing. Returns the same input!!! Be careful
          return {
            data: data,
            rows: nRows,
            cols: nCols
          };
        var output = new Array(rows * cols);
        var shiftR = Math.floor((rows - nRows) / 2) - nRows;
        var shiftC = Math.floor((cols - nCols) / 2) - nCols;

        for (i = 0; i < rows; i++) {
          irow = i * cols;
          icol = (i - shiftR) % nRows * nCols;

          for (j = 0; j < cols; j++) {
            output[irow + j] = data[icol + (j - shiftC) % nCols];
          }
        }

        return {
          data: output,
          rows: rows,
          cols: cols
        };
      },

      /**
       * Crop the given matrix to fit the corresponding number of rows and columns
       */
      crop: function (data, rows, cols, nRows, nCols, opt) {
        if (rows == nRows && cols == nCols) //Do nothing. Returns the same input!!! Be careful
          return data;
        Object.assign({}, opt);
        var output = new Array(nCols * nRows);
        var shiftR = Math.floor((rows - nRows) / 2);
        var shiftC = Math.floor((cols - nCols) / 2);
        var destinyRow, sourceRow, i, j;

        for (i = 0; i < nRows; i++) {
          destinyRow = i * nCols;
          sourceRow = (i + shiftR) * cols;

          for (j = 0; j < nCols; j++) {
            output[destinyRow + j] = data[sourceRow + (j + shiftC)];
          }
        }

        return output;
      }
    };
    var FFTUtils_1 = FFTUtils$1;

    var FFTUtils = src.FFTUtils = FFTUtils_1;
    src.FFT = fftlib;

    function matrix2Array(input) {
      let inputData = input;
      let nRows, nCols;

      if (typeof input[0] !== 'number') {
        nRows = input.length;
        nCols = input[0].length;
        inputData = new Array(nRows * nCols);

        for (let i = 0; i < nRows; i++) {
          for (let j = 0; j < nCols; j++) {
            inputData[i * nCols + j] = input[i][j];
          }
        }
      } else {
        let tmp = Math.sqrt(input.length);

        if (Number.isInteger(tmp)) {
          nRows = tmp;
          nCols = tmp;
        }
      }

      return {
        data: inputData,
        rows: nRows,
        cols: nCols
      };
    }

    function convolutionFFT(input, kernel, opt) {
      let tmp = matrix2Array(input);
      let inputData = tmp.data;
      let options = Object.assign({
        normalize: false,
        divisor: 1,
        rows: tmp.rows,
        cols: tmp.cols
      }, opt);
      let nRows, nCols;

      if (options.rows && options.cols) {
        nRows = options.rows;
        nCols = options.cols;
      } else {
        throw new Error(`Invalid number of rows or columns ${nRows} ${nCols}`);
      }

      let divisor = options.divisor;
      let kHeight = kernel.length;
      let kWidth = kernel[0].length;

      if (options.normalize) {
        divisor = 0;

        for (let i = 0; i < kHeight; i++) {
          for (let j = 0; j < kWidth; j++) divisor += kernel[i][j];
        }
      }

      if (divisor === 0) {
        throw new RangeError('convolution: The divisor is equal to zero');
      }

      let radix2Sized = FFTUtils.toRadix2(inputData, nRows, nCols);
      let conv = FFTUtils.convolute(radix2Sized.data, kernel, radix2Sized.rows, radix2Sized.cols);
      conv = FFTUtils.crop(conv, radix2Sized.rows, radix2Sized.cols, nRows, nCols);

      if (divisor !== 0 && divisor !== 1) {
        for (let i = 0; i < conv.length; i++) {
          conv[i] /= divisor;
        }
      }

      return conv;
    }

    function convolutionDirect(input, kernel, opt) {
      let tmp = matrix2Array(input);
      let inputData = tmp.data;
      let options = Object.assign({
        normalize: false,
        divisor: 1,
        rows: tmp.rows,
        cols: tmp.cols
      }, opt);
      let nRows, nCols;

      if (options.rows && options.cols) {
        nRows = options.rows;
        nCols = options.cols;
      } else {
        throw new Error(`Invalid number of rows or columns ${nRows} ${nCols}`);
      }

      let divisor = options.divisor;
      let kHeight = kernel.length;
      let kWidth = kernel[0].length;
      let index, sum, kVal, row, col;

      if (options.normalize) {
        divisor = 0;

        for (let i = 0; i < kHeight; i++) {
          for (let j = 0; j < kWidth; j++) divisor += kernel[i][j];
        }
      }

      if (divisor === 0) {
        throw new RangeError('convolution: The divisor is equal to zero');
      }

      let output = new Array(nRows * nCols);
      let hHeight = Math.floor(kHeight / 2);
      let hWidth = Math.floor(kWidth / 2);

      for (let y = 0; y < nRows; y++) {
        for (let x = 0; x < nCols; x++) {
          sum = 0;

          for (let j = 0; j < kHeight; j++) {
            for (let i = 0; i < kWidth; i++) {
              kVal = kernel[kHeight - j - 1][kWidth - i - 1];
              row = (y + j - hHeight + nRows) % nRows;
              col = (x + i - hWidth + nCols) % nCols;
              index = row * nCols + col;
              sum += inputData[index] * kVal;
            }
          }

          index = y * nCols + x;
          output[index] = sum / divisor;
        }
      }

      return output;
    }

    /**
     * @class DisjointSet
     */


    class DisjointSet {
      constructor() {
        this.nodes = new Map();
      }
      /**
       * Adds an element as a new set
       * @param {*} value
       * @return {DisjointSetNode} Object holding the element
       */


      add(value) {
        var node = this.nodes.get(value);

        if (!node) {
          node = new DisjointSetNode(value);
          this.nodes.set(value, node);
        }

        return node;
      }
      /**
       * Merges the sets that contain x and y
       * @param {DisjointSetNode} x
       * @param {DisjointSetNode} y
       */


      union(x, y) {
        const rootX = this.find(x);
        const rootY = this.find(y);

        if (rootX === rootY) {
          return;
        }

        if (rootX.rank < rootY.rank) {
          rootX.parent = rootY;
        } else if (rootX.rank > rootY.rank) {
          rootY.parent = rootX;
        } else {
          rootY.parent = rootX;
          rootX.rank++;
        }
      }
      /**
       * Finds and returns the root node of the set that contains node
       * @param {DisjointSetNode} node
       * @return {DisjointSetNode}
       */


      find(node) {
        var rootX = node;

        while (rootX.parent !== null) {
          rootX = rootX.parent;
        }

        var toUpdateX = node;

        while (toUpdateX.parent !== null) {
          var toUpdateParent = toUpdateX;
          toUpdateX = toUpdateX.parent;
          toUpdateParent.parent = rootX;
        }

        return rootX;
      }
      /**
       * Returns true if x and y belong to the same set
       * @param {DisjointSetNode} x
       * @param {DisjointSetNode} y
       */


      connected(x, y) {
        return this.find(x) === this.find(y);
      }

    }

    var DisjointSet_1 = DisjointSet;

    function DisjointSetNode(value) {
      this.value = value;
      this.parent = null;
      this.rank = 0;
    }

    var DisjointSet$1 = DisjointSet_1;

    const direction8X$2 = [-1, -1, 0, 1, -1, 0, 1, 1];
    const direction8Y$2 = [0, -1, -1, -1, 1, 1, 1, 0];
    const neighbours8$1 = [null, null, null, null, null, null, null, null];
    const direction4X$1 = [-1, 0, 1, 0];
    const direction4Y$1 = [0, -1, 0, 1];
    const neighbours4$1 = [null, null, null, null];
    function drainLabelling(data, mask) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      const {
        neighbours = 8,
        width,
        height
      } = options;
      let directionX;
      let directionY;
      let neighboursList;

      if (neighbours === 8) {
        directionX = direction8X$2;
        directionY = direction8Y$2;
        neighboursList = neighbours8$1;
      } else if (neighbours === 4) {
        directionX = direction4X$1;
        directionY = direction4Y$1;
        neighboursList = neighbours4$1;
      } else {
        throw new RangeError(`unsupported neighbours count: ${neighbours}`);
      }

      let sorted = new Array(height * width);

      for (let i = 0, index = 0; i < height; i++) {
        for (let j = 0; j < width; j++, index++) {
          sorted[index] = {
            value: data[index],
            row: i,
            col: j,
            mask: mask[index]
          };
        }
      }

      sorted.sort((a, b) => a.value - b.value);
      const size = mask.length;
      const labels = new Array(size);
      const pixels = new Int16Array(size);
      const linked = new DisjointSet$1();

      for (let i = 0, currentLabel = 1; i < mask.length; i++) {
        let element = sorted[i];
        if (!element.mask) continue;
        let {
          row,
          col,
          value
        } = element;
        let index = col + row * width;
        let label = labels[index];

        if (!label) {
          labels[index] = linked.add(currentLabel++);
        }

        for (let k = 0; k < neighboursList.length; k++) {
          let ii = col + directionX[k];
          let jj = row + directionY[k];

          if (ii >= 0 && jj >= 0 && ii < width && jj < height) {
            let neighbor = labels[ii + jj * width];

            if (!neighbor) {
              let neighborValue = data[ii + jj * width];

              if (value < neighborValue) {
                labels[ii + jj * width] = labels[index];
              }
            }
          }
        }
      }

      for (let j = 0; j < height; j++) {
        for (let i = 0; i < width; i++) {
          let index = i + j * width;

          if (mask[index]) {
            pixels[index] = linked.find(labels[index]).value;
          }
        }
      }

      return pixels;
    }

    const direction4X = [-1, 0];
    const direction4Y = [0, -1];
    const neighbours4 = [null, null];
    const direction8X$1 = [-1, -1, 0, 1];
    const direction8Y$1 = [0, -1, -1, -1];
    const neighbours8 = [null, null, null, null];
    function floodFillLabelling(mask, width, height, options) {
      options = options || {};
      const neighbours = options.neighbours || 8;
      let directionX;
      let directionY;
      let neighboursList;

      if (neighbours === 8) {
        directionX = direction8X$1;
        directionY = direction8Y$1;
        neighboursList = neighbours8;
      } else if (neighbours === 4) {
        directionX = direction4X;
        directionY = direction4Y;
        neighboursList = neighbours4;
      } else {
        throw new RangeError(`unsupported neighbours count: ${neighbours}`);
      }

      const size = mask.length;
      const labels = new Array(size);
      const pixels = new Int16Array(size);
      const linked = new DisjointSet$1();
      let index;
      let currentLabel = 1;

      for (let j = 0; j < height; j++) {
        for (let i = 0; i < width; i++) {
          // true means out of background
          let smallestNeighbor = null;
          index = i + j * width;

          if (mask[index]) {
            for (let k = 0; k < neighboursList.length; k++) {
              let ii = i + directionX[k];
              let jj = j + directionY[k];

              if (ii >= 0 && jj >= 0 && ii < width && jj < height) {
                let neighbor = labels[ii + jj * width];

                if (!neighbor) {
                  neighboursList[k] = null;
                } else {
                  neighboursList[k] = neighbor;

                  if (!smallestNeighbor || neighboursList[k].value < smallestNeighbor.value) {
                    smallestNeighbor = neighboursList[k];
                  }
                }
              }
            }

            if (!smallestNeighbor) {
              labels[index] = linked.add(currentLabel++);
            } else {
              labels[index] = smallestNeighbor;

              for (let k = 0; k < neighboursList.length; k++) {
                if (neighboursList[k] && neighboursList[k] !== smallestNeighbor) {
                  linked.union(smallestNeighbor, neighboursList[k]);
                }
              }
            }
          }
        }
      }

      for (let j = 0; j < height; j++) {
        for (let i = 0; i < width; i++) {
          index = i + j * width;

          if (mask[index]) {
            pixels[index] = linked.find(labels[index]).value;
          }
        }
      }

      return pixels;
    }

    const smallFilter$1 = [[0, 0, 1, 2, 2, 2, 1, 0, 0], [0, 1, 4, 7, 7, 7, 4, 1, 0], [1, 4, 5, 3, 0, 3, 5, 4, 1], [2, 7, 3, -12, -23, -12, 3, 7, 2], [2, 7, 0, -23, -40, -23, 0, 7, 2], [2, 7, 3, -12, -23, -12, 3, 7, 2], [1, 4, 5, 3, 0, 3, 5, 4, 1], [0, 1, 3, 7, 7, 7, 3, 1, 0], [0, 0, 1, 2, 2, 2, 1, 0, 0]];
    /**
     * Detects all the 2D-peaks in the given spectrum based on center of mass logic.
     * @param {Array<Array>} input - matrix to get the local maxima
     * @param {Object} [options = {}] - options of the method.
     * @param {Array<Array>} [options.nStdDev = 3] - number of times of the standard deviations for the noise level.Float64Array
     * @param {Array<Array>} [options.kernel] - kernel to the convolution step.
     * @param {string} [options.labelling = 'drain'] - select the labelling algorithm to assign pixels.
     * @param {Array<Array>} [options.originalData] - original data useful when the original matrix has values and the input matrix has absolute ones
     * @param {Array<Array>} [options.filteredData] - convoluted data, if it is defined the convolution step is skipped
     */

    function findPeaks2DRegion(input) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        nStdDev = 3,
        kernel = smallFilter$1,
        originalData = matrix2Array(input).data,
        filteredData,
        rows: nRows,
        cols: nCols,
        labelling = 'drain'
      } = options;
      let flatten = matrix2Array(input);
      let data = flatten.data;

      if (!nRows || !nCols) {
        nRows = flatten.rows;
        nCols = flatten.cols;
      }

      if (!nRows || !nCols) {
        throw new Error(`Invalid number of rows or columns ${nRows} ${nCols}`);
      }

      let cs = filteredData;
      if (!cs) cs = convolutionFFT(data, kernel, options);
      let threshold = 0;

      for (let i = nCols * nRows - 2; i >= 0; i--) {
        threshold += Math.pow(cs[i] - cs[i + 1], 2);
      }

      threshold = -Math.sqrt(threshold) * nStdDev / nRows;
      let bitmask = new Uint16Array(nCols * nRows);

      for (let i = cs.length - 1; i >= 0; i--) {
        if (cs[i] < threshold) {
          bitmask[i] = 1;
        }
      }

      let pixels;

      switch (labelling.toLowerCase()) {
        case 'drain':
          pixels = drainLabelling(cs, bitmask, {
            neighbours: 8,
            width: nCols,
            height: nRows
          });
          break;

        case 'floodfill':
          pixels = floodFillLabelling(bitmask, nCols, nRows, {
            neighbours: 8
          });
          break;

        default:
          throw new Error(`labelling ${labelling} does not support`);
      }

      return extractPeaks(pixels, {
        data,
        nCols,
        originalData
      });
    }

    function extractPeaks(pixels, options) {
      const {
        data,
        nCols,
        originalData
      } = options; //How many different groups we have?

      let labels = {};
      let row, col, tmp;

      for (let i = 0; i < pixels.length; i++) {
        if (pixels[i] !== 0) {
          col = i % nCols;
          row = (i - col) / nCols;

          if (labels[pixels[i]]) {
            tmp = labels[pixels[i]];
            tmp.x += col * data[i];
            tmp.y += row * data[i];
            tmp.z += originalData[i];
            if (col < tmp.minX) tmp.minX = col;
            if (col > tmp.maxX) tmp.maxX = col;
            if (row < tmp.minY) tmp.minY = row;
            if (row > tmp.maxY) tmp.maxY = row;
          } else {
            labels[pixels[i]] = {
              x: col * data[i],
              y: row * data[i],
              z: originalData[i],
              minX: col,
              maxX: col,
              minY: row,
              maxY: row
            };
          }
        }
      }

      let keys = Object.keys(labels);
      let peakList = new Array(keys.length);

      for (let i = 0; i < keys.length; i++) {
        peakList[i] = labels[keys[i]];
        let zValue = Math.abs(peakList[i].z);
        peakList[i].x /= zValue;
        peakList[i].y /= zValue;
      }

      return peakList;
    }

    const {
      parse: parse$2,
      stringify: stringify$2
    } = JSON;
    function addMissingIDs(peaks) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        output = parse$2(stringify$2(peaks))
      } = options;

      for (const peak of output) {
        if (!('id' in peak)) {
          peak.id = v4();
        }
      }

      return output;
    }

    const direction8X = [-1, -1, -1, 0, 0, 1, 1, 1];
    const direction8Y = [-1, 0, 1, -1, 1, -1, 0, 1];
    const direction16X = [-2, -2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 2, 2, 2];
    const direction16Y = [-2, -1, 0, 1, 2, -2, 2, -2, 2, -2, 2, -2, -1, 0, 1, 2];
    function determineRealTop(peaks, options) {
      let {
        nCols,
        absoluteData,
        originalData,
        minX,
        maxX,
        minY,
        maxY
      } = options;

      for (let i = 0; i < peaks.length; i++) {
        let xIndex = Math.round(peaks[i].x);
        let yIndex = Math.round(peaks[i].y);
        let currentIndex = xIndex + yIndex * nCols;
        let {
          index,
          isMax
        } = determineMax(absoluteData, {
          xIndex,
          yIndex,
          nCols,
          shell: 1
        });
        currentIndex = isMax ? index : determineMax(absoluteData, {
          xIndex,
          yIndex,
          nCols,
          shell: 2
        }).index;
        let realTopCoordinates = fitGaussian(originalData, {
          nCols,
          index: currentIndex,
          minY,
          maxY,
          minX,
          maxX
        });
        peaks[i] = Object.assign(peaks[i], realTopCoordinates);
      }

      return peaks;
    }

    function determineMax(data, options) {
      let {
        xIndex,
        yIndex,
        shell,
        nCols
      } = options;
      let currentIndex = xIndex + yIndex * nCols;
      let [directionX, directionY] = shell > 1 ? [direction16X, direction16Y] : [direction8X, direction8Y];
      let isMax = false;

      for (let i = 0; i < directionX.length; i++) {
        let c = xIndex + directionX[i];
        let r = yIndex + directionY[i];

        if (data[c + r * nCols] >= data[currentIndex]) {
          isMax = true;
          let candidateIndex = c + r * nCols;

          for (let k = 0; k < direction8Y.length; k++) {
            let nc = c + direction8X[k];
            let nr = r + direction8Y[k];

            if (data[nc + nr * nCols] > data[candidateIndex]) {
              isMax = false;
              break;
            }
          }

          if (isMax) {
            currentIndex = candidateIndex;
          }
        }
      }

      return {
        index: currentIndex,
        isMax
      };
    }

    function fitGaussian(data, options) {
      let {
        nCols,
        index,
        minY,
        maxY,
        minX,
        maxX
      } = options;
      let nRows = data.length / nCols;
      let intervalX = (maxX - minX) / (nCols - 1);
      let intervalY = (maxY - minY) / (nRows - 1);
      let col = index % nCols;
      let row = (index - col) / nCols;
      let newCol = 1;
      let newRow = 1;
      let max = Number.MIN_SAFE_INTEGER;
      let z = new Array(direction8X.length + 1);
      let xAxis = new Array(direction8X.length + 1);

      for (let i = -1, xi = 0; i < 2; i++) {
        for (let j = -1; j < 2; j++, xAxis[xi] = xi++) {
          let value = data[col + j + (row + i) * nCols];
          if (max < value) max = value;
          z[newCol + j + (newRow + i) * 3] = value;
        }
      }

      for (let i = 0; i < z.length; i++) z[i] /= max;

      let maxValues = [newCol + 1, newRow + 1, 1.5, 1, 1];
      let minValues = [newCol - 1, newRow - 1, -1.5, 0.001, 0.001];
      let initialValues = [newCol, newRow, z[newCol + newRow * 3], 0.2, 0.2];
      let gradientDifference = [1e-4, 1e-4, 1e-3, 1e-3, 1e-3];
      let func = paramGaussian2D(intervalX, intervalY, 3);
      let pFit = levenbergMarquardt({
        x: xAxis,
        y: z
      }, func, {
        damping: 1.5,
        maxIterations: 100,
        errorTolerance: 1e-8,
        initialValues,
        gradientDifference,
        maxValues,
        minValues
      }).parameterValues;
      return {
        x: pFit[0] + col - 1,
        y: pFit[1] + row - 1,
        z: pFit[2] * max
      };
    }

    function paramGaussian2D(intervalX, intervalY, nCols) {
      const gaussian2D = new Gaussian2D();
      return p => {
        return t => {
          let nL = p.length / 5;
          let result = 0;
          let xIndex = t % nCols;
          let yIndex = (t - xIndex) / nCols;

          for (let i = 0; i < nL; i++) {
            gaussian2D.fwhm = {
              x: p[i + 3 * nL],
              y: p[i + 4 * nL]
            };
            result += p[i + 2 * nL] * gaussian2D.fct((xIndex - p[i]) * intervalX, (yIndex - p[i + nL]) * intervalY);
          }

          return result;
        };
      };
    }

    function getKernel() {
      let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      let {
        sigma = 1.4,
        xLength = 9,
        yLength = 9
      } = options;
      let factor = -40 / laplacianOfGaussian(0, 0, sigma);
      const xCenter = (xLength - 1) / 2;
      const yCenter = (yLength - 1) / 2;
      let matrix = new Array(xLength);

      for (let x = 0; x < xLength; x++) {
        matrix[x] = new Array(yLength);

        for (let y = 0; y < yLength; y++) {
          matrix[x][y] = laplacianOfGaussian(x - xCenter, y - yCenter, sigma) * factor;
        }
      }

      return matrix;
    }

    const laplacianOfGaussian = (x, y, sigma) => {
      let factor = -(Math.pow(x, 2) + Math.pow(y, 2)) / 2 / Math.pow(sigma, 2);
      return -(1 / Math.PI / Math.pow(sigma, 4)) * (1 + factor) * Math.exp(factor);
    };

    let diagonalError = 0.05;
    let tolerance = 0.05;
    function clean(peaks, threshold) {
      let max = Number.NEGATIVE_INFINITY; // double min = Double.MAX_VALUE;

      for (let i = peaks.length - 1; i >= 0; i--) {
        if (Math.abs(peaks[i].z) > max) {
          max = Math.abs(peaks[i].z);
        }
      }

      max *= threshold;

      for (let i = peaks.length - 1; i >= 0; i--) {
        if (Math.abs(peaks[i].z) < max) {
          peaks.splice(i, 1);
        }
      }

      return peaks;
    }
    function enhanceSymmetry(signals) {
      let properties = initializeProperties(signals);
      let output = signals.slice(); // First step of the optimization: Symmetry validation

      let hits;

      for (let i = output.length - 1; i >= 0; i--) {
        let signal = output[i];

        if (signal.peaks && signal.peaks.length > 1) {
          properties[i][1]++;
        }

        if (properties[i][0] === 1) {
          let index = exist(output, properties, signal, -1, true);

          if (index >= 0) {
            properties[i][1] += 2;
            properties[index][1] += 2;
          }
        }
      } // Second step of the optimization: Diagonal image existence


      for (let i = output.length - 1; i >= 0; i--) {
        let signal = output[i];

        if (properties[i][0] === 0) {
          hits = checkCrossPeaks(output, properties, signal, true);
          properties[i][1] += hits; // checkCrossPeaks(output, properties, signal, false);
        }
      } // Now, each peak have a score between 0 and 4, we can complete the patterns which
      // contains peaks with high scores, and finally, we can remove peaks with scores 0 and 1


      let count = 0;

      for (let i = output.length - 1; i >= 0; i--) {
        if (properties[i][0] !== 0 && properties[i][1] > 2) {
          count++;
          count += completeMissingIfNeeded(output, properties, output[i], properties[i]);
        }

        if (properties[i][1] >= 2 && properties[i][0] === 0) {
          count++;
        }
      }

      let toReturn = new Array(count);
      count--;

      for (let i = output.length - 1; i >= 0; i--) {
        if (properties[i][0] !== 0 && properties[i][1] > 2 || properties[i][0] === 0 && properties[i][1] > 1) {
          toReturn[count--] = output[i];
        }
      }

      return toReturn;
    } // export function alignDimensions(signals2D, references) {
    //   // For each reference dimension
    //   for (let i = 0; i < references.length; i++) {
    //     let ref = references[i];
    //     if (ref) {
    //       alignSingleDimension(signals2D, ref);
    //     }
    //   }
    // }

    function completeMissingIfNeeded(output, properties, thisSignal, thisProp) {
      // Check for symmetry
      let index = exist(output, properties, thisSignal, -thisProp[0], true);
      let addedPeaks = 0;
      let newSignal;
      let tmpProp = null;

      if (index < 0) {
        // If this signal have no a symmetry image, we have to include it
        newSignal = {
          x: {
            nucleus: thisSignal.x.nucleus,
            resolution: thisSignal.x.resolution,
            delta: thisSignal.y.delta
          },
          y: {
            nucleus: thisSignal.y.nucleus,
            resolution: thisSignal.y.resolution,
            delta: thisSignal.x.delta
          },
          peaks: [{
            x: thisSignal.y.delta,
            y: thisSignal.x.delta,
            z: 1
          }]
        };
        output.push(newSignal);
        tmpProp = [-thisProp[0], thisProp[1]];
        properties.push(tmpProp);
        addedPeaks++;
      } // Check for diagonal peaks


      let signal;
      let diagX = false;
      let diagY = false;

      for (let j = output.length - 1; j >= 0; j--) {
        signal = output[j];

        if (properties[j][0] === 0) {
          if (Math.abs(signal.x.delta - thisSignal.x.delta) < diagonalError) {
            diagX = true;
          }

          if (Math.abs(signal.y.delta - thisSignal.y.delta) < diagonalError) {
            diagY = true;
          }
        }
      }

      if (!diagX) {
        newSignal = {
          x: {
            delta: thisSignal.y.delta,
            nucleus: thisSignal.x.nucleus,
            resolution: thisSignal.x.resolution
          },
          y: {
            delta: thisSignal.x.delta,
            nucleus: thisSignal.y.nucleus,
            resolution: thisSignal.y.resolution
          },
          peaks: [{
            x: thisSignal.x.delta,
            y: thisSignal.x.delta,
            z: 1
          }]
        };
        newSignal.peaks = [{
          x: thisSignal.x.delta,
          y: thisSignal.x.delta,
          z: 1
        }];
        output.push(newSignal);
        tmpProp = [0, thisProp[1]];
        properties.push(tmpProp);
        addedPeaks++;
      }

      if (!diagY) {
        newSignal = {
          x: {
            delta: thisSignal.y.delta,
            nucleus: thisSignal.x.nucleus,
            resolution: thisSignal.x.resolution
          },
          y: {
            delta: thisSignal.y.delta,
            nucleus: thisSignal.y.nucleus,
            resolution: thisSignal.y.resolution
          },
          peaks: [{
            x: thisSignal.y.delta,
            y: thisSignal.y.delta,
            z: 1
          }]
        };
        output.push(newSignal);
        tmpProp = [0, thisProp[1]];
        properties.push(tmpProp);
        addedPeaks++;
      }

      return addedPeaks;
    } // Check for any diagonal peak that match this cross peak


    function checkCrossPeaks(output, properties, signal, updateProperties) {
      let hits = 0;
      let shift = signal.x.delta * 4;
      let crossPeaksX = [];
      let crossPeaksY = [];
      let cross;

      for (let i = output.length - 1; i >= 0; i--) {
        cross = output[i];

        if (properties[i][0] !== 0) {
          if (Math.abs(cross.x.delta - signal.x.delta) < diagonalError) {
            hits++;

            if (updateProperties) {
              properties[i][1]++;
            }

            crossPeaksX.push(i);
            shift += cross.x.delta;
          } else if (Math.abs(cross.y.delta - signal.y.delta) < diagonalError) {
            hits++;

            if (updateProperties) {
              properties[i][1]++;
            }

            crossPeaksY.push(i);
            shift += cross.y.delta;
          }
        }
      } // Update found crossPeaks and diagonal peak


      shift /= crossPeaksX.length + crossPeaksY.length + 4;

      if (crossPeaksX.length > 0) {
        for (let i = crossPeaksX.length - 1; i >= 0; i--) {
          output[crossPeaksX[i]].x.delta = shift;
        }
      }

      if (crossPeaksY.length > 0) {
        for (let i = crossPeaksY.length - 1; i >= 0; i--) {
          output[crossPeaksY[i]].y.delta = shift;
        }
      }

      signal.x.delta = shift;
      signal.y.delta = shift;
      return hits;
    }

    function exist(output, properties, signal, type, symmetricSearch) {
      for (let i = output.length - 1; i >= 0; i--) {
        if (properties[i][0] === type) {
          if (distanceTo(signal, output[i], symmetricSearch) < tolerance) {
            if (!symmetricSearch) {
              let shiftX = (output[i].x.delta + signal.x.delta) / 2.0;
              let shiftY = (output[i].y.delta + signal.y.delta) / 2.0;
              output[i].x.delta = shiftX;
              output[i].y.delta = shiftY;
              signal.x.delta = shiftX;
              signal.y.delta = shiftY;
            } else {
              let shiftX = signal.x.delta;
              let shiftY = output[i].x.delta;
              output[i].y.delta = shiftX;
              signal.y.delta = shiftY;
            }

            return i;
          }
        }
      }

      return -1;
    }
    /**
     * Try to determine the position of each signal within the spectrum matrix.
     * Peaks could be of 3 types: upper diagonal, diagonal or under diagonal 1,0,-1
     * respectively.
     * @param {Array} signals
     * @return {*} A matrix containing the properties of each signal
     * @private
     */


    function initializeProperties(signals) {
      let signalsProperties = new Array(signals.length);

      for (let i = signals.length - 1; i >= 0; i--) {
        signalsProperties[i] = [0, 0]; // We check if it is a diagonal peak

        if (Math.abs(signals[i].x.delta - signals[i].y.delta) <= diagonalError) {
          signalsProperties[i][1] = 1;
          let shift = (signals[i].x.delta * 2 + signals[i].y.delta) / 3.0;
          signals[i].x.delta = shift;
          signals[i].y.delta = shift;
        } else if (signals[i].x.delta - signals[i].y.delta > 0) {
          signalsProperties[i][0] = 1;
        } else {
          signalsProperties[i][0] = -1;
        }
      }

      return signalsProperties;
    }
    /**
     * This function calculates the distance between 2 nmr signals . If toImage is true,
     * it will interchange x by y in the distance calculation for the second signal.
     * @param {object} a
     * @param {object} b
     * @param {boolean} toImage
     * @return {number}
     * @private
     */


    function distanceTo(a, b, toImage) {
      if (!toImage) {
        return Math.sqrt(Math.pow(a.x.delta - b.x.delta, 2) + Math.pow(a.y.delta - b.y.delta, 2));
      } else {
        return Math.sqrt(Math.pow(a.x.delta - b.y.delta, 2) + Math.pow(a.y.delta - b.x.delta, 2));
      }
    } // type Signal2DWithHighlight = MakeMandatory<NMRSignal2D, '_highlight'>;
    // function checkHighlight(signals2D: NMRSignal2D[]): asserts signals2D is Signal2DwithHighlight[] {
    //   for (let signal of signals2D) {
    //     if (!signal._highlight) throw new Error('there is not _hightlight property');
    //     if (!signal.nucleusX) throw new Error('there is not nucleusX property');
    //     if (!signal.nucleusY) throw new Error('there is not nucleusY property')
    //   }
    // }
    // function alignSingleDimension(signals2D: NMRSignal2D[], references) {
    //   // For each 2D signal
    //   for (let i = 0; i < signals2D.length; i++) {
    //     let signal2D = signals2D[i];
    //     for (let j = 0; j < references.length; j++) {
    //       const center = (references[j].startX + references[j].stopX) / 2;
    //       const width = Math.abs(references[j].startX - references[j].stopX) / 2;
    //       if (signal2D.nucleusX === references[j].nucleus) {
    //         // The 2D peak overlaps with the 1D signal
    //         if (Math.abs(signal2D.x.delta - center) <= width) {
    //           signal2D._highlight.push(references[j]._highlight[0]);
    //         }
    //       }
    //       if (signal2D.nucleusY === references[j].nucleus) {
    //         if (Math.abs(signal2D.y.delta - center) <= width) {
    //           signal2D._highlight.push(references[j]._highlight[0]);
    //         }
    //       }
    //     }
    //   }
    // }

    function formatZones(signals) {
      let zones = [];

      for (const signal of signals) {
        let minMax1 = [Number.MAX_VALUE, 0];
        let minMax2 = [Number.MAX_VALUE, 0];

        for (const peak of signal.peaks || []) {
          if (peak.minX < minMax1[0]) {
            minMax1[0] = peak.minX;
          }

          if (peak.maxX > minMax1[1]) {
            minMax1[1] = peak.maxX;
          }

          if (peak.minY < minMax2[0]) {
            minMax2[0] = peak.minY;
          }

          if (peak.maxY > minMax2[1]) {
            minMax2[1] = peak.maxY;
          }
        }

        zones.push({
          id: v4(),
          x: {
            from: minMax1[0],
            to: minMax1[1]
          },
          y: {
            from: minMax2[0],
            to: minMax2[1]
          },
          signals: [signal]
        });
      }

      return zones;
    }

    const smallFilter = [[0, 0, 1, 2, 2, 2, 1, 0, 0], [0, 1, 4, 7, 7, 7, 4, 1, 0], [1, 4, 5, 3, 0, 3, 5, 4, 1], [2, 7, 3, -12, -23, -12, 3, 7, 2], [2, 7, 0, -23, -40, -23, 0, 7, 2], [2, 7, 3, -12, -23, -12, 3, 7, 2], [1, 4, 5, 3, 0, 3, 5, 4, 1], [0, 1, 3, 7, 7, 7, 3, 1, 0], [0, 0, 1, 2, 2, 2, 1, 0, 0]];
    function xyzAutoZonesPicking(spectraData, options) {
      let {
        sizeToPad = 14,
        realTopDetection = true,
        thresholdFactor = 0.5,
        nuclei = ['1H', '1H'],
        observedFrequencies,
        enhanceSymmetry: enhanceSymmetry$1 = false,
        clean: clean$1 = true,
        maxPercentCutOff = 0.03,
        tolerances = [24, 24],
        convolutionByFFT = true,
        kernel: kernelOptions
      } = options;

      if (!Array.isArray(observedFrequencies) && !ArrayBuffer.isView(observedFrequencies)) {
        throw new Error('observedFrequencies is mandatory');
      }

      thresholdFactor = thresholdFactor === 0 ? 1 : Math.abs(thresholdFactor);
      let nbPoints = spectraData.z[0].length;
      let nbSubSpectra = spectraData.z.length;

      if (nbSubSpectra < sizeToPad) {
        spectraData = padData(spectraData, {
          width: sizeToPad
        });
        nbPoints = spectraData.z[0].length;
        nbSubSpectra = spectraData.z.length;
      }

      let absoluteData = new Float64Array(nbPoints * nbSubSpectra);
      let originalData = new Float64Array(nbPoints * nbSubSpectra);

      for (let iSubSpectra = 0; iSubSpectra < nbSubSpectra; iSubSpectra++) {
        let spectrum = spectraData.z[iSubSpectra];

        for (let iCol = 0; iCol < nbPoints; iCol++) {
          let index = iSubSpectra * nbPoints + iCol;
          absoluteData[index] = Math.abs(spectrum[iCol]);
          originalData[index] = spectrum[iCol]; //@todo pensar si se puede evitar originalData
        }
      }

      const kernel = kernelOptions ? getKernel(kernelOptions) : smallFilter;
      let convolutedSpectrum = convolutionByFFT ? convolutionFFT(absoluteData, kernel, {
        rows: nbSubSpectra,
        cols: nbPoints
      }) : convolutionDirect(absoluteData, kernel, {
        rows: nbSubSpectra,
        cols: nbPoints
      });
      let peaksMC1 = findPeaks2DRegion(absoluteData, {
        originalData,
        filteredData: convolutedSpectrum,
        rows: nbSubSpectra,
        cols: nbPoints,
        nStdDev: thresholdFactor
      });

      if (clean$1) {
        // Remove peaks with less than x% of the intensity of the highest peak
        peaksMC1 = clean(peaksMC1, maxPercentCutOff);
      }

      let signals = createSignals2D$1(addMissingIDs(peaksMC1), {
        nRows: nbSubSpectra,
        nCols: nbPoints,
        minX: spectraData.minX,
        maxX: spectraData.maxX,
        minY: spectraData.minY,
        maxY: spectraData.maxY,
        absoluteData,
        originalData,
        tolerances,
        nuclei,
        observedFrequencies,
        realTopDetection
      });

      if (enhanceSymmetry$1) {
        signals = enhanceSymmetry(signals);
      }

      return formatZones(signals);
    }

    function createSignals2D$1(peaks, options) {
      let {
        nCols,
        nRows,
        absoluteData,
        originalData,
        observedFrequencies,
        tolerances,
        nuclei,
        realTopDetection,
        minY,
        maxY,
        minX,
        maxX
      } = options;
      let [nucleusX, nucleusY] = nuclei;
      let [toleranceX, toleranceY] = tolerances;
      let [observeFrequencyX, observeFrequencyY] = observedFrequencies;
      let dy = (maxY - minY) / (nRows - 1);
      let dx = (maxX - minX) / (nCols - 1);

      if (realTopDetection) {
        peaks = determineRealTop(peaks, {
          nCols,
          absoluteData,
          originalData,
          minX,
          maxX,
          minY,
          maxY
        });
      }

      for (let i = peaks.length - 1; i >= 0; i--) {
        let {
          x,
          y
        } = peaks[i];
        peaks[i].x = minX + dx * x;
        peaks[i].y = minY + dy * y;
        peaks[i].minX = minX + dx * peaks[i].minX;
        peaks[i].minY = minY + dy * peaks[i].minY;
        peaks[i].maxX = minX + dx * peaks[i].maxX;
        peaks[i].maxY = minY + dy * peaks[i].maxY; // Still having problems to correctly detect peaks on those areas. So I'm removing everything there.
      } // The connectivity matrix is an square and symmetric matrix, so we'll only store the upper diagonal in an
      // array like form


      let connectivity = [];

      for (let i = 0; i < peaks.length; i++) {
        for (let j = i; j < peaks.length; j++) {
          if (Math.abs(peaks[i].x - peaks[j].x) * observeFrequencyX < toleranceX && Math.abs(peaks[i].y - peaks[j].y) * observeFrequencyY < toleranceY) {
            // 24*24Hz We cannot distinguish peaks with less than 20 Hz of separation
            connectivity.push(1);
          } else {
            connectivity.push(0);
          }
        }
      }

      let clusters = simpleClustering(connectivity);
      let signals = [];

      if (clusters) {
        for (const cluster of clusters) {
          let signal = {
            id: v4(),
            x: {
              delta: 0,
              nucleus: nucleusX,
              resolution: dx
            },
            y: {
              delta: 0,
              nucleus: nucleusY,
              resolution: dy
            }
          };
          let peaks2D = [];
          let sumZ = 0;

          for (let jPeak = 0; jPeak < cluster.length; jPeak++) {
            if (cluster[jPeak] === 1) {
              peaks2D.push(peaks[jPeak]);
              signal.x.delta += peaks[jPeak].x * peaks[jPeak].z;
              signal.y.delta += peaks[jPeak].y * peaks[jPeak].z;
              sumZ += peaks[jPeak].z;
            }
          }

          signal.x.delta /= sumZ;
          signal.y.delta /= sumZ;
          signal.peaks = peaks2D;
          signals.push(signal);
        }
      }

      return signals;
    }

    function padData(spectraData, options) {
      let {
        minX,
        maxX,
        minY,
        maxY
      } = spectraData;
      const width = options.width;
      let nbPoints = spectraData.z[0].length;
      let nbSubSpectra = spectraData.z.length;
      let yInterval = (maxY - minY) / (nbSubSpectra - 1);
      let xInterval = (maxX - minX) / (nbPoints - 1);
      let yDiff = width - nbSubSpectra;
      let xDiff = Math.max(width - nbPoints, 0);
      if (xDiff % 2) xDiff++;
      if (yDiff % 2) yDiff++;
      let xOffset = xDiff / 2;
      let yOffset = yDiff / 2;
      let newMatrix = Matrix.zeros(nbSubSpectra + yDiff, nbPoints + xDiff);

      for (let i = 0; i < nbSubSpectra; i++) {
        for (let j = 0; j < nbPoints; j++) {
          newMatrix.set(i + yOffset, j + xOffset, spectraData.z[i][j]);
        }
      }

      return {
        z: newMatrix.to2DArray(),
        minX: minX - xOffset * xInterval,
        maxX: maxX + xOffset * xInterval,
        minY: minY - yOffset * yInterval,
        maxY: maxY + yOffset * yInterval
      };
    }

    const {
      parse: parse$1,
      stringify: stringify$1
    } = JSON;
    function xyzJResAnalyzer(signals) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let {
        reference = 0,
        getZones = false,
        referenceMaxShiftError = 0.08,
        tolerances = [10, 100],
        nuclei = ['1H', '1H'],
        observedFrequencies = [400, 400],
        jAnalyzer = {
          jAxisKey: {
            jAxis: 'y',
            intensity: 'z'
          }
        }
      } = options;
      let temporalSignals = compilePattern(signals, {
        observedFrequencies,
        tolerances,
        nuclei,
        jAnalyzer
      }); //check if the signal are symmetric around the reference

      let signals2D = [];

      for (const tempSignal of temporalSignals) {
        let delta = tempSignal.y.delta;
        if (Math.abs(delta - reference) > referenceMaxShiftError) continue;
        signals2D.push(tempSignal);
      }

      signals2D = addMissingIDs(signals2D);
      return getZones ? formatZones(signals2D) : signals2D;
    }

    function compilePattern(signals, options) {
      let {
        observedFrequencies,
        tolerances,
        nuclei,
        jAnalyzer: jAnalyzerOptions
      } = options;
      let signalOptions = {
        observedFrequencies,
        tolerances,
        nuclei,
        dx: signals[0].x.resolution,
        dy: signals[0].y.resolution
      };
      const defaultWidth = 0.02 * observedFrequencies[0];
      const newSignals = parse$1(stringify$1(signals)); //adapt to 1D jAnalyzer

      for (const signal of newSignals) {
        let peaks = signal.peaks;
        signal.nbPeaks = signal.peaks.length;
        signal.multiplicity = '';
        signal.pattern = '';
        signal.delta1 = signal.shiftY;
        signal.observe = observedFrequencies[1];
        signal.integralData = {
          from: Number.MAX_SAFE_INTEGER,
          to: Number.MIN_SAFE_INTEGER
        };

        for (const peak of peaks) {
          if (!peak.width) peak.width = defaultWidth;
        }

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

      for (let i = 0; i < signals.length; i++) {
        jAnalyzer.compilePattern(newSignals[i], jAnalyzerOptions);

        if (newSignals[i].maskPattern && newSignals[i].multiplicity !== 'm' && newSignals[i].multiplicity !== '') {
          // Create a new signal with the removed peaks
          let peaksO = [];

          for (let j = newSignals[i].maskPattern.length - 1; j >= 0; j--) {
            if (newSignals[i].maskPattern[j] === false) {
              let peakR = newSignals[i].peaks.splice(j, 1)[0];
              peaksO.push(peakR);
              newSignals[i].mask.splice(j, 1);
              newSignals[i].mask2.splice(j, 1);
              newSignals[i].maskPattern.splice(j, 1);
              newSignals[i].nbPeaks--;
            }
          }

          if (peaksO.length > 0) {
            peaksO.reverse();
            let signals2D = createSignals2D(peaksO, signalOptions);

            for (const signal of signals2D) {
              newSignals.push(signal);
            }
          }
        }
      }

      signals.sort((a, b) => {
        return b.x.delta - a.x.delta;
      });
      return signals;
    }

    function createSignals2D(peaksInput, options) {
      let {
        observedFrequencies,
        tolerances,
        nuclei,
        dx,
        dy
      } = options;
      const peaks = parse$1(stringify$1(peaksInput));
      let [nucleusX, nucleusY] = nuclei;
      let [toleranceX, toleranceY] = tolerances;
      let [observeFrequencyX, observeFrequencyY] = observedFrequencies; // The connectivity matrix is an square and symmetric matrix, so we'll only store the upper diagonal in an
      // array like form

      let connectivity = [];

      for (let i = 0; i < peaks.length; i++) {
        for (let j = i; j < peaks.length; j++) {
          if (Math.abs(peaks[i].x - peaks[j].x) * observeFrequencyX < toleranceX && Math.abs(peaks[i].y - peaks[j].y) * observeFrequencyY < toleranceY) {
            // 24*24Hz We cannot distinguish peaks with less than 20 Hz of separation
            connectivity.push(1);
          } else {
            connectivity.push(0);
          }
        }
      }

      let clusters = simpleClustering(connectivity);
      let signals = [];

      if (clusters) {
        for (let cluster of clusters) {
          let signal = {
            id: v4(),
            nucleusX,
            nucleusY,
            integralData: {
              from: Number.MAX_SAFE_INTEGER,
              to: Number.MIN_SAFE_INTEGER
            },
            nbPeaks: 0,
            multiplicity: '',
            pattern: '',
            observe: observeFrequencyY,
            resolutionX: dx,
            resolutionY: dy,
            shiftX: 0,
            shiftY: 0
          };
          let peaks2D = [];
          let minMax1 = [Number.MAX_VALUE, 0];
          let minMax2 = [Number.MAX_VALUE, 0];
          let sumZ = 0;

          for (let jPeak = cluster.length - 1; jPeak >= 0; jPeak--) {
            if (cluster[jPeak] === 1) {
              signal.nbPeaks++;
              if (!peaks[jPeak].width) peaks[jPeak].width = 0.02;
              peaks2D.push(peaks[jPeak]);
              signal.shiftX += peaks[jPeak].x * peaks[jPeak].z;
              signal.shiftY += peaks[jPeak].y * peaks[jPeak].z;
              sumZ += peaks[jPeak].z;

              if (peaks[jPeak].minX < minMax1[0]) {
                minMax1[0] = peaks[jPeak].minX;
              }

              if (peaks[jPeak].maxX > minMax1[1]) {
                minMax1[1] = peaks[jPeak].maxX;
              }

              if (peaks[jPeak].minY < minMax2[0]) {
                minMax2[0] = peaks[jPeak].minY;
              }

              if (peaks[jPeak].maxY > minMax2[1]) {
                minMax2[1] = peaks[jPeak].maxY;
              }
            }
          }

          signal.fromTo = [{
            from: minMax1[0],
            to: minMax1[1]
          }, {
            from: minMax2[0],
            to: minMax2[1]
          }];
          signal.shiftX /= sumZ;
          signal.shiftY /= sumZ;
          signal.delta1 = signal.shiftY;
          signal.peaks = peaks2D;
          signals.push(signal);
        }
      }

      return signals;
    }

    async function getDatabase() {
      let url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'https://docs.google.com/spreadsheets/d/1uwyq_L38PMRWCcT4If_EhPbHKyY3q_2tpjV8vr5_zh0/edit?usp=sharing';
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        format = 'tsv'
      } = options;

      if (url.includes('google.com')) {
        url = `https://googledocs.cheminfo.org/spreadsheets/d/${extractGoogleUUID(url)}/export?format=tsv`;
      }

      let parsed;
      const response = await browserPonyfill.exports.fetch(url);

      switch (format) {
        case 'tsv':
          parsed = parseData(await response.text());
          break;

        case 'json':
          parsed = await response.json();
          break;

        default:
          throw new Error('unknown database format');
      }

      const results = [];

      for (let line of parsed.data) {
        const result = {
          smiles: '',
          solvent: '',
          nucleus: '',
          jcampURL: '',
          names: [],
          meta: {},
          ranges: []
        };

        for (let i = 0; i < line.length; i++) {
          switch (parsed.kinds[i]) {
            case 'smiles':
              result.smiles = line[i];
              break;

            case 'solvent':
              result.solvent = line[i];
              break;

            case 'nucleus':
              result.nucleus = line[i];
              break;

            case 'jcampURL':
              result.jcampURL = line[i];
              break;

            case 'name':
              if (result.names) result.names.push(line[i]);
              break;

            case 'meta':
              if (result.meta) result.meta[parsed.labels[i]] = line[i];
              break;

            case 'signal':
              {
                const range = resurrectRange(line[i]);
                if (range) result.ranges.push(range);
                break;
              }

            default:
              throw new Error(`Unknown column kind: ${parsed.kinds[i]}`);
          }
        }

        results.push(result);
      }

      return results;
    }

    function extractGoogleUUID(url) {
      return url.replace(/.*\/(?<uuid>[^/]{20,50}).*/, '$<uuid>');
    }

    function parseData(text) {
      const matrix = text.split(/\r?\n/).filter(line => !/^\s*$/.exec(line)).map(line => line.split('\t').map(cell => cell.trim()));
      const labels = matrix[0];
      const kinds = matrix[1];
      const data = matrix.slice(2);
      return {
        labels,
        kinds,
        data
      };
    }

    const carbonImpurities = [{
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 171.69,
          assignment: 'CO'
        }],
        from: 171.68625,
        to: 171.69375
      }, {
        signals: [{
          delta: 20.13,
          assignment: 'CH₃'
        }],
        from: 20.12625,
        to: 20.13375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 204.19,
          assignment: 'CO'
        }],
        from: 204.18625,
        to: 204.19375
      }, {
        signals: [{
          delta: 30.17,
          assignment: 'CH₃'
        }],
        from: 30.16625,
        to: 30.173750000000002
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 116.79,
          assignment: 'CN'
        }],
        from: 116.78625000000001,
        to: 116.79375
      }, {
        signals: [{
          delta: 0.45,
          assignment: 'CH₃'
        }],
        from: 0.44625000000000004,
        to: 0.45375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 128.84,
          assignment: 'CH'
        }],
        from: 128.83625,
        to: 128.84375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 67.5,
          assignment: '(CH₃)₃C'
        }],
        from: 67.49625,
        to: 67.50375
      }, {
        signals: [{
          delta: 30.57,
          assignment: '(CH₃)₃C'
        }],
        from: 30.56625,
        to: 30.57375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 125.69,
          assignment: 'CO₂'
        }],
        from: 125.68625,
        to: 125.69375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 193.37,
          assignment: 'CS₂'
        }],
        from: 193.36625,
        to: 193.37375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.89,
          assignment: 'CCl₄'
        }],
        from: 96.88625,
        to: 96.89375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 79.24,
          assignment: 'CH'
        }],
        from: 79.23625,
        to: 79.24374999999999
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 71.34,
          assignment: 'CH₂'
        }],
        from: 71.33625,
        to: 71.34375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 27.58,
          assignment: 'CH₂'
        }],
        from: 27.576249999999998,
        to: 27.58375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 44.64,
          assignment: 'CH₂'
        }],
        from: 44.636250000000004,
        to: 44.64375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 54.67,
          assignment: 'CH₂'
        }],
        from: 54.666250000000005,
        to: 54.67375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.49,
          assignment: 'CH₃'
        }],
        from: 15.48625,
        to: 15.49375
      }, {
        signals: [{
          delta: 66.14,
          assignment: 'CH₂'
        }],
        from: 66.13625,
        to: 66.14375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.72,
          assignment: 'CH₃'
        }],
        from: 58.71625,
        to: 58.723749999999995
      }, {
        signals: [{
          delta: 71.17,
          assignment: 'CH₂'
        }],
        from: 71.16625,
        to: 71.17375
      }, {
        signals: [{
          delta: 72.72,
          assignment: 'CH₂'
        }],
        from: 72.71625,
        to: 72.72375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 161.96,
          assignment: 'CH'
        }],
        from: 161.95625,
        to: 161.96375
      }, {
        signals: [{
          delta: 35.65,
          assignment: 'CH₃'
        }],
        from: 35.64625,
        to: 35.653749999999995
      }, {
        signals: [{
          delta: 30.7,
          assignment: 'CH₃'
        }],
        from: 30.69625,
        to: 30.70375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.65,
          assignment: 'CH₂'
        }],
        from: 67.64625000000001,
        to: 67.65375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.72,
          assignment: 'CH₃'
        }],
        from: 58.71625,
        to: 58.723749999999995
      }, {
        signals: [{
          delta: 72.58,
          assignment: 'CH₂'
        }],
        from: 72.57625,
        to: 72.58375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.79,
          assignment: 'CH₃'
        }],
        from: 6.78625,
        to: 6.79375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.9,
          assignment: 'CH₃'
        }],
        from: 18.89625,
        to: 18.90375
      }, {
        signals: [{
          delta: 57.6,
          assignment: 'CH₂'
        }],
        from: 57.596250000000005,
        to: 57.60375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 20.45,
          assignment: 'CH₃CO'
        }],
        from: 20.44625,
        to: 20.45375
      }, {
        signals: [{
          delta: 170.32,
          assignment: 'CO'
        }],
        from: 170.31625,
        to: 170.32375
      }, {
        signals: [{
          delta: 60.3,
          assignment: 'CH₂'
        }],
        from: 60.29625,
        to: 60.303749999999994
      }, {
        signals: [{
          delta: 14.37,
          assignment: 'CH₃'
        }],
        from: 14.366249999999999,
        to: 14.37375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 123.09,
          assignment: 'CH₂'
        }],
        from: 123.08625,
        to: 123.09375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.35,
          assignment: 'CH₂'
        }],
        from: 64.34625,
        to: 64.35374999999999
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 30.45,
          assignment: 'CH₂'
        }],
        from: 30.44625,
        to: 30.45375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 131.88,
          assignment: 'C'
        }],
        from: 131.87625,
        to: 131.88375
      }, {
        signals: [{
          delta: 16.71,
          assignment: 'CH₃'
        }],
        from: 16.70625,
        to: 16.71375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.22,
          assignment: 'CH₃'
        }],
        from: 14.21625,
        to: 14.22375
      }, {
        signals: [{
          delta: 23.33,
          assignment: 'CH₂(2,5)'
        }],
        from: 23.326249999999998,
        to: 23.33375
      }, {
        signals: [{
          delta: 32.34,
          assignment: 'CH₂(3,4)'
        }],
        from: 32.33625000000001,
        to: 32.34375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 1.83,
          assignment: 'CH₃'
        }],
        from: 1.8262500000000002,
        to: 1.83375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.89,
          assignment: 'CH₃'
        }],
        from: 36.886250000000004,
        to: 36.89375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.72,
          assignment: 'CH(2)'
        }],
        from: 135.71625,
        to: 135.72375
      }, {
        signals: [{
          delta: 122.2,
          assignment: 'CH(4,5)'
        }],
        from: 122.19625,
        to: 122.20375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.9,
          assignment: 'CH₄'
        }],
        from: -4.9037500000000005,
        to: -4.89625
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.64,
          assignment: 'CH₃'
        }],
        from: 49.636250000000004,
        to: 49.64375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 62.49,
          assignment: 'CH₃'
        }],
        from: 62.486250000000005,
        to: 62.49375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.18,
          assignment: 'CH₃'
        }],
        from: 14.17625,
        to: 14.18375
      }, {
        signals: [{
          delta: 23,
          assignment: 'CH₂(2,4)'
        }],
        from: 22.99625,
        to: 23.00375
      }, {
        signals: [{
          delta: 34.87,
          assignment: 'CH₂(3)'
        }],
        from: 34.86625,
        to: 34.873749999999994
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.6,
          assignment: 'CH₃'
        }],
        from: 16.59625,
        to: 16.60375
      }, {
        signals: [{
          delta: 16.82,
          assignment: 'CH₂'
        }],
        from: 16.81625,
        to: 16.82375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.7,
          assignment: 'CH₃'
        }],
        from: 25.69625,
        to: 25.70375
      }, {
        signals: [{
          delta: 66.14,
          assignment: 'CH'
        }],
        from: 66.13625,
        to: 66.14375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.27,
          assignment: 'CH₃'
        }],
        from: 19.26625,
        to: 19.27375
      }, {
        signals: [{
          delta: 115.74,
          assignment: 'CH₂'
        }],
        from: 115.73625,
        to: 115.74374999999999
      }, {
        signals: [{
          delta: 134.02,
          assignment: 'CH'
        }],
        from: 134.01625,
        to: 134.02375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 150.57,
          assignment: 'CH(2,6)'
        }],
        from: 150.56625,
        to: 150.57375
      }, {
        signals: [{
          delta: 124.08,
          assignment: 'CH(3,5)'
        }],
        from: 124.07625,
        to: 124.08375
      }, {
        signals: [{
          delta: 135.99,
          assignment: 'CH(4)'
        }],
        from: 135.98625,
        to: 135.99375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 118.03,
          assignment: 'CH(2,5)'
        }],
        from: 118.02625,
        to: 118.03375
      }, {
        signals: [{
          delta: 107.74,
          assignment: 'CH(3,4)'
        }],
        from: 107.73625,
        to: 107.74374999999999
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 45.82,
          assignment: 'CH₂(2,5)'
        }],
        from: 45.816250000000004,
        to: 45.82375
      }, {
        signals: [{
          delta: 26.17,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.16625,
        to: 26.173750000000002
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 1.2,
          assignment: 'CH₃'
        }],
        from: 1.19625,
        to: 1.2037499999999999
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 68.03,
          assignment: 'CH₂(2,5)'
        }],
        from: 68.02625,
        to: 68.03375
      }, {
        signals: [{
          delta: 26.19,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.18625,
        to: 26.19375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.29,
          assignment: 'CH₃'
        }],
        from: 21.28625,
        to: 21.29375
      }, {
        signals: [{
          delta: 138.24,
          assignment: 'C(1)'
        }],
        from: 138.23625,
        to: 138.24375
      }, {
        signals: [{
          delta: 129.47,
          assignment: 'CH(2,6)'
        }],
        from: 129.46625,
        to: 129.47375
      }, {
        signals: [{
          delta: 128.71,
          assignment: 'CH(3,5)'
        }],
        from: 128.70625,
        to: 128.71375
      }, {
        signals: [{
          delta: 125.84,
          assignment: 'CH(4)'
        }],
        from: 125.83625,
        to: 125.84375
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 12.51,
          assignment: 'CH₃'
        }],
        from: 12.50625,
        to: 12.51375
      }, {
        signals: [{
          delta: 47.18,
          assignment: 'CH₂'
        }],
        from: 47.17625,
        to: 47.183749999999996
      }],
      nucleus: '13C',
      solvent: 'THF-d₈'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 175.85,
          assignment: 'CO'
        }],
        from: 175.84625,
        to: 175.85375
      }, {
        signals: [{
          delta: 20.91,
          assignment: 'CH₃'
        }],
        from: 20.90625,
        to: 20.91375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 206.78,
          assignment: 'CO'
        }],
        from: 206.77625,
        to: 206.78375
      }, {
        signals: [{
          delta: 31,
          assignment: 'CH₃'
        }],
        from: 30.99625,
        to: 31.00375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 116.92,
          assignment: 'CN'
        }],
        from: 116.91625,
        to: 116.92375
      }, {
        signals: [{
          delta: 2.03,
          assignment: 'CH₃'
        }],
        from: 2.0262499999999997,
        to: 2.03375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 128.68,
          assignment: 'CH'
        }],
        from: 128.67625,
        to: 128.68375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 69.11,
          assignment: '(CH₃)₃C'
        }],
        from: 69.10625,
        to: 69.11375
      }, {
        signals: [{
          delta: 31.46,
          assignment: '(CH₃)₃C'
        }],
        from: 31.45625,
        to: 31.46375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 125.26,
          assignment: 'CO₂'
        }],
        from: 125.25625000000001,
        to: 125.26375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 192.95,
          assignment: 'CS₂'
        }],
        from: 192.94625,
        to: 192.95374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.52,
          assignment: 'CCl₄'
        }],
        from: 96.51625,
        to: 96.52374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 77.99,
          assignment: 'CH'
        }],
        from: 77.98625,
        to: 77.99374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 70.47,
          assignment: 'CH₂'
        }],
        from: 70.46625,
        to: 70.47375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 27.38,
          assignment: 'CH₂'
        }],
        from: 27.37625,
        to: 27.38375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 44.35,
          assignment: 'CH₂'
        }],
        from: 44.346250000000005,
        to: 44.35375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 54.24,
          assignment: 'CH₂'
        }],
        from: 54.236250000000005,
        to: 54.24375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.44,
          assignment: 'CH₃'
        }],
        from: 15.43625,
        to: 15.44375
      }, {
        signals: [{
          delta: 66.11,
          assignment: 'CH₂'
        }],
        from: 66.10625,
        to: 66.11375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.95,
          assignment: 'CH₃'
        }],
        from: 58.946250000000006,
        to: 58.95375
      }, {
        signals: [{
          delta: 70.7,
          assignment: 'CH₂'
        }],
        from: 70.69625,
        to: 70.70375
      }, {
        signals: [{
          delta: 72.25,
          assignment: 'CH₂'
        }],
        from: 72.24625,
        to: 72.25375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 162.57,
          assignment: 'CH'
        }],
        from: 162.56625,
        to: 162.57375
      }, {
        signals: [{
          delta: 36.56,
          assignment: 'CH₃'
        }],
        from: 36.556250000000006,
        to: 36.56375
      }, {
        signals: [{
          delta: 31.39,
          assignment: 'CH₃'
        }],
        from: 31.38625,
        to: 31.39375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.47,
          assignment: 'CH₂'
        }],
        from: 67.46625,
        to: 67.47375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 59.02,
          assignment: 'CH₃'
        }],
        from: 59.01625000000001,
        to: 59.02375
      }, {
        signals: [{
          delta: 72.24,
          assignment: 'CH₂'
        }],
        from: 72.23625,
        to: 72.24374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.91,
          assignment: 'CH₃'
        }],
        from: 6.90625,
        to: 6.91375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.69,
          assignment: 'CH₃'
        }],
        from: 18.68625,
        to: 18.69375
      }, {
        signals: [{
          delta: 58.57,
          assignment: 'CH₂'
        }],
        from: 58.566250000000004,
        to: 58.57375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 21.15,
          assignment: 'CH₃CO'
        }],
        from: 21.14625,
        to: 21.15375
      }, {
        signals: [{
          delta: 171.24,
          assignment: 'CO'
        }],
        from: 171.23625,
        to: 171.24375
      }, {
        signals: [{
          delta: 60.63,
          assignment: 'CH₂'
        }],
        from: 60.626250000000006,
        to: 60.63375
      }, {
        signals: [{
          delta: 14.37,
          assignment: 'CH₃'
        }],
        from: 14.366249999999999,
        to: 14.37375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 123.2,
          assignment: 'CH₂'
        }],
        from: 123.19625,
        to: 123.20375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.08,
          assignment: 'CH₂'
        }],
        from: 64.07625,
        to: 64.08375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 30.14,
          assignment: 'CH₂'
        }],
        from: 30.13625,
        to: 30.14375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 132.09,
          assignment: 'C'
        }],
        from: 132.08625,
        to: 132.09375
      }, {
        signals: [{
          delta: 16.93,
          assignment: 'CH₃'
        }],
        from: 16.92625,
        to: 16.93375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.28,
          assignment: 'CH₃'
        }],
        from: 14.27625,
        to: 14.28375
      }, {
        signals: [{
          delta: 23.07,
          assignment: 'CH₂(2,5)'
        }],
        from: 23.06625,
        to: 23.07375
      }, {
        signals: [{
          delta: 32.01,
          assignment: 'CH₂(3,4)'
        }],
        from: 32.00625,
        to: 32.013749999999995
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 1.96,
          assignment: 'CH₃'
        }],
        from: 1.95625,
        to: 1.9637499999999999
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.99,
          assignment: 'CH₃'
        }],
        from: 36.986250000000005,
        to: 36.99375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.76,
          assignment: 'CH(2)'
        }],
        from: 135.75625,
        to: 135.76375
      }, {
        signals: [{
          delta: 122.16,
          assignment: 'CH(4,5)'
        }],
        from: 122.15625,
        to: 122.16375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.33,
          assignment: 'CH₄'
        }],
        from: -4.33375,
        to: -4.32625
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 50.45,
          assignment: 'CH₃'
        }],
        from: 50.446250000000006,
        to: 50.45375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 63.03,
          assignment: 'CH₃'
        }],
        from: 63.026250000000005,
        to: 63.03375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.24,
          assignment: 'CH₃'
        }],
        from: 14.23625,
        to: 14.24375
      }, {
        signals: [{
          delta: 22.77,
          assignment: 'CH₂(2,4)'
        }],
        from: 22.76625,
        to: 22.77375
      }, {
        signals: [{
          delta: 34.57,
          assignment: 'CH₂(3)'
        }],
        from: 34.566250000000004,
        to: 34.57375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.63,
          assignment: 'CH₃'
        }],
        from: 16.62625,
        to: 16.63375
      }, {
        signals: [{
          delta: 16.63,
          assignment: 'CH₂'
        }],
        from: 16.62625,
        to: 16.63375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.43,
          assignment: 'CH₃'
        }],
        from: 25.42625,
        to: 25.43375
      }, {
        signals: [{
          delta: 64.67,
          assignment: 'CH'
        }],
        from: 64.66625,
        to: 64.67375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.47,
          assignment: 'CH₃'
        }],
        from: 19.46625,
        to: 19.47375
      }, {
        signals: [{
          delta: 115.7,
          assignment: 'CH₂'
        }],
        from: 115.69625,
        to: 115.70375
      }, {
        signals: [{
          delta: 134.21,
          assignment: 'CH'
        }],
        from: 134.20625,
        to: 134.21375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 150.27,
          assignment: 'CH(2,6)'
        }],
        from: 150.26625,
        to: 150.27375
      }, {
        signals: [{
          delta: 124.06,
          assignment: 'CH(3,5)'
        }],
        from: 124.05625,
        to: 124.06375
      }, {
        signals: [{
          delta: 136.16,
          assignment: 'CH(4)'
        }],
        from: 136.15625,
        to: 136.16375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 117.93,
          assignment: 'CH(2,5)'
        }],
        from: 117.92625000000001,
        to: 117.93375
      }, {
        signals: [{
          delta: 108.02,
          assignment: 'CH(3,4)'
        }],
        from: 108.01625,
        to: 108.02374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 47.02,
          assignment: 'CH₂(2,5)'
        }],
        from: 47.01625000000001,
        to: 47.02375
      }, {
        signals: [{
          delta: 25.83,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.826249999999998,
        to: 25.83375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 1.22,
          assignment: 'CH₃'
        }],
        from: 1.21625,
        to: 1.22375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 68.16,
          assignment: 'CH₂(2,5)'
        }],
        from: 68.15625,
        to: 68.16375
      }, {
        signals: [{
          delta: 25.98,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.97625,
        to: 25.98375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.53,
          assignment: 'CH₃'
        }],
        from: 21.52625,
        to: 21.53375
      }, {
        signals: [{
          delta: 138.36,
          assignment: 'C(1)'
        }],
        from: 138.35625000000002,
        to: 138.36375
      }, {
        signals: [{
          delta: 129.35,
          assignment: 'CH(2,6)'
        }],
        from: 129.34625,
        to: 129.35375
      }, {
        signals: [{
          delta: 128.54,
          assignment: 'CH(3,5)'
        }],
        from: 128.53625,
        to: 128.54375
      }, {
        signals: [{
          delta: 125.62,
          assignment: 'CH(4)'
        }],
        from: 125.61625000000001,
        to: 125.62375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 12.12,
          assignment: 'CH₃'
        }],
        from: 12.116249999999999,
        to: 12.12375
      }, {
        signals: [{
          delta: 46.75,
          assignment: 'CH₂'
        }],
        from: 46.74625,
        to: 46.75375
      }],
      nucleus: '13C',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 175.99,
          assignment: 'CO'
        }],
        from: 175.98625,
        to: 175.99375
      }, {
        signals: [{
          delta: 20.81,
          assignment: 'CH₃'
        }],
        from: 20.80625,
        to: 20.81375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 207.07,
          assignment: 'CO'
        }],
        from: 207.06625,
        to: 207.07375
      }, {
        signals: [{
          delta: 30.92,
          assignment: 'CH₃'
        }],
        from: 30.91625,
        to: 30.923750000000002
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 116.43,
          assignment: 'CN'
        }],
        from: 116.42625000000001,
        to: 116.43375
      }, {
        signals: [{
          delta: 1.89,
          assignment: 'CH₃'
        }],
        from: 1.88625,
        to: 1.8937499999999998
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 128.37,
          assignment: 'CH'
        }],
        from: 128.36625,
        to: 128.37375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 69.15,
          assignment: '(CH₃)₃C'
        }],
        from: 69.14625000000001,
        to: 69.15375
      }, {
        signals: [{
          delta: 31.25,
          assignment: '(CH₃)₃C'
        }],
        from: 31.24625,
        to: 31.25375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 124.99,
          assignment: 'CO₂'
        }],
        from: 124.98625,
        to: 124.99374999999999
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 192.83,
          assignment: 'CS₂'
        }],
        from: 192.82625000000002,
        to: 192.83375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.34,
          assignment: 'CCl₄'
        }],
        from: 96.33625,
        to: 96.34375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 77.36,
          assignment: 'CH'
        }],
        from: 77.35625,
        to: 77.36375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 70.55,
          assignment: 'CH₂'
        }],
        from: 70.54625,
        to: 70.55375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 26.94,
          assignment: 'CH₂'
        }],
        from: 26.93625,
        to: 26.94375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 43.5,
          assignment: 'CH₂'
        }],
        from: 43.49625,
        to: 43.50375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 53.52,
          assignment: 'CH₂'
        }],
        from: 53.51625000000001,
        to: 53.52375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.2,
          assignment: 'CH₃'
        }],
        from: 15.19625,
        to: 15.20375
      }, {
        signals: [{
          delta: 65.91,
          assignment: 'CH₂'
        }],
        from: 65.90625,
        to: 65.91375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 59.01,
          assignment: 'CH₃'
        }],
        from: 59.00625,
        to: 59.013749999999995
      }, {
        signals: [{
          delta: 70.51,
          assignment: 'CH₂'
        }],
        from: 70.50625000000001,
        to: 70.51375
      }, {
        signals: [{
          delta: 71.9,
          assignment: 'CH₂'
        }],
        from: 71.89625000000001,
        to: 71.90375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 162.62,
          assignment: 'CH'
        }],
        from: 162.61625,
        to: 162.62375
      }, {
        signals: [{
          delta: 36.5,
          assignment: 'CH₃'
        }],
        from: 36.49625,
        to: 36.50375
      }, {
        signals: [{
          delta: 31.45,
          assignment: 'CH₃'
        }],
        from: 31.44625,
        to: 31.45375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.14,
          assignment: 'CH₂'
        }],
        from: 67.13625,
        to: 67.14375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 59.08,
          assignment: 'CH₃'
        }],
        from: 59.07625,
        to: 59.083749999999995
      }, {
        signals: [{
          delta: 71.84,
          assignment: 'CH₂'
        }],
        from: 71.83625,
        to: 71.84375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.89,
          assignment: 'CH₃'
        }],
        from: 6.8862499999999995,
        to: 6.89375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.41,
          assignment: 'CH₃'
        }],
        from: 18.40625,
        to: 18.41375
      }, {
        signals: [{
          delta: 58.28,
          assignment: 'CH₂'
        }],
        from: 58.276250000000005,
        to: 58.28375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 21.04,
          assignment: 'CH₃CO'
        }],
        from: 21.03625,
        to: 21.04375
      }, {
        signals: [{
          delta: 171.36,
          assignment: 'CO'
        }],
        from: 171.35625000000002,
        to: 171.36375
      }, {
        signals: [{
          delta: 60.49,
          assignment: 'CH₂'
        }],
        from: 60.486250000000005,
        to: 60.49375
      }, {
        signals: [{
          delta: 14.19,
          assignment: 'CH₃'
        }],
        from: 14.18625,
        to: 14.19375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 123.13,
          assignment: 'CH₂'
        }],
        from: 123.12625,
        to: 123.13374999999999
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 63.79,
          assignment: 'CH₂'
        }],
        from: 63.78625,
        to: 63.793749999999996
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 29.71,
          assignment: 'CH₂'
        }],
        from: 29.70625,
        to: 29.71375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 132.21,
          assignment: 'C'
        }],
        from: 132.20625,
        to: 132.21375
      }, {
        signals: [{
          delta: 16.98,
          assignment: 'CH₃'
        }],
        from: 16.97625,
        to: 16.98375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.14,
          assignment: 'CH₃'
        }],
        from: 14.13625,
        to: 14.14375
      }, {
        signals: [{
          delta: 22.7,
          assignment: 'CH₂(2,5)'
        }],
        from: 22.69625,
        to: 22.70375
      }, {
        signals: [{
          delta: 31.64,
          assignment: 'CH₂(3,4)'
        }],
        from: 31.63625,
        to: 31.64375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 1.97,
          assignment: 'CH₃'
        }],
        from: 1.96625,
        to: 1.97375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.87,
          assignment: 'CH₃'
        }],
        from: 36.86625,
        to: 36.873749999999994
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.38,
          assignment: 'CH(2)'
        }],
        from: 135.37625,
        to: 135.38375
      }, {
        signals: [{
          delta: 122,
          assignment: 'CH(4,5)'
        }],
        from: 121.99625,
        to: 122.00375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.63,
          assignment: 'CH₄'
        }],
        from: -4.63375,
        to: -4.62625
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 50.41,
          assignment: 'CH₃'
        }],
        from: 50.40625,
        to: 50.41374999999999
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 62.5,
          assignment: 'CH₃'
        }],
        from: 62.49625,
        to: 62.50375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.08,
          assignment: 'CH₃'
        }],
        from: 14.07625,
        to: 14.08375
      }, {
        signals: [{
          delta: 22.38,
          assignment: 'CH₂(2,4)'
        }],
        from: 22.37625,
        to: 22.38375
      }, {
        signals: [{
          delta: 34.16,
          assignment: 'CH₂(3)'
        }],
        from: 34.15625,
        to: 34.16374999999999
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.63,
          assignment: 'CH₃'
        }],
        from: 16.62625,
        to: 16.63375
      }, {
        signals: [{
          delta: 16.37,
          assignment: 'CH₂'
        }],
        from: 16.36625,
        to: 16.37375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.14,
          assignment: 'CH₃'
        }],
        from: 25.13625,
        to: 25.14375
      }, {
        signals: [{
          delta: 64.5,
          assignment: 'CH'
        }],
        from: 64.49625,
        to: 64.50375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.5,
          assignment: 'CH₃'
        }],
        from: 19.49625,
        to: 19.50375
      }, {
        signals: [{
          delta: 115.74,
          assignment: 'CH₂'
        }],
        from: 115.73625,
        to: 115.74374999999999
      }, {
        signals: [{
          delta: 133.91,
          assignment: 'CH'
        }],
        from: 133.90625,
        to: 133.91375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 149.9,
          assignment: 'CH(2,6)'
        }],
        from: 149.89625,
        to: 149.90375
      }, {
        signals: [{
          delta: 123.75,
          assignment: 'CH(3,5)'
        }],
        from: 123.74625,
        to: 123.75375
      }, {
        signals: [{
          delta: 135.96,
          assignment: 'CH(4)'
        }],
        from: 135.95625,
        to: 135.96375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 117.77,
          assignment: 'CH(2,5)'
        }],
        from: 117.76625,
        to: 117.77374999999999
      }, {
        signals: [{
          delta: 107.98,
          assignment: 'CH(3,4)'
        }],
        from: 107.97625000000001,
        to: 107.98375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 46.93,
          assignment: 'CH₂(2,5)'
        }],
        from: 46.92625,
        to: 46.933749999999996
      }, {
        signals: [{
          delta: 25.56,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.55625,
        to: 25.56375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 1.19,
          assignment: 'CH₃'
        }],
        from: 1.18625,
        to: 1.1937499999999999
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 67.97,
          assignment: 'CH₂(2,5)'
        }],
        from: 67.96625,
        to: 67.97375
      }, {
        signals: [{
          delta: 25.62,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.61625,
        to: 25.62375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.46,
          assignment: 'CH₃'
        }],
        from: 21.45625,
        to: 21.46375
      }, {
        signals: [{
          delta: 137.89,
          assignment: 'C(1)'
        }],
        from: 137.88625,
        to: 137.89374999999998
      }, {
        signals: [{
          delta: 129.07,
          assignment: 'CH(2,6)'
        }],
        from: 129.06625,
        to: 129.07375
      }, {
        signals: [{
          delta: 128.26,
          assignment: 'CH(3,5)'
        }],
        from: 128.25625,
        to: 128.26375
      }, {
        signals: [{
          delta: 125.33,
          assignment: 'CH(4)'
        }],
        from: 125.32625,
        to: 125.33375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 11.61,
          assignment: 'CH₃'
        }],
        from: 11.60625,
        to: 11.61375
      }, {
        signals: [{
          delta: 46.25,
          assignment: 'CH₂'
        }],
        from: 46.24625,
        to: 46.25375
      }],
      nucleus: '13C',
      solvent: 'CDCl₃'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 175.3,
          assignment: 'CO'
        }],
        from: 175.29625000000001,
        to: 175.30375
      }, {
        signals: [{
          delta: 20.27,
          assignment: 'CH₃'
        }],
        from: 20.26625,
        to: 20.27375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 204,
          assignment: 'CO'
        }],
        from: 203.99625,
        to: 204.00375
      }, {
        signals: [{
          delta: 30.03,
          assignment: 'CH₃'
        }],
        from: 30.02625,
        to: 30.03375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 115.76,
          assignment: 'CN'
        }],
        from: 115.75625000000001,
        to: 115.76375
      }, {
        signals: [{
          delta: 0.03,
          assignment: 'CH₃'
        }],
        from: 0.02625,
        to: 0.03375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 128.57,
          assignment: 'CH'
        }],
        from: 128.56625,
        to: 128.57375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 68.12,
          assignment: '(CH₃)₃C'
        }],
        from: 68.11625000000001,
        to: 68.12375
      }, {
        signals: [{
          delta: 30.49,
          assignment: '(CH₃)₃C'
        }],
        from: 30.48625,
        to: 30.49375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 124.86,
          assignment: 'CO₂'
        }],
        from: 124.85625,
        to: 124.86375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 192.71,
          assignment: 'CS₂'
        }],
        from: 192.70625,
        to: 192.71375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.57,
          assignment: 'CCl₄'
        }],
        from: 96.56625,
        to: 96.57374999999999
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 77.89,
          assignment: 'CH'
        }],
        from: 77.88625,
        to: 77.89375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 70.86,
          assignment: 'CH₂'
        }],
        from: 70.85625,
        to: 70.86375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 27.31,
          assignment: 'CH₂'
        }],
        from: 27.30625,
        to: 27.31375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 43.4,
          assignment: 'CH₂'
        }],
        from: 43.39625,
        to: 43.403749999999995
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 53.47,
          assignment: 'CH₂'
        }],
        from: 53.46625,
        to: 53.473749999999995
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.47,
          assignment: 'CH₃'
        }],
        from: 15.46625,
        to: 15.47375
      }, {
        signals: [{
          delta: 65.94,
          assignment: 'CH₂'
        }],
        from: 65.93625,
        to: 65.94375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.62,
          assignment: 'CH₃'
        }],
        from: 58.61625,
        to: 58.623749999999994
      }, {
        signals: [{
          delta: 70.92,
          assignment: 'CH₂'
        }],
        from: 70.91625,
        to: 70.92375
      }, {
        signals: [{
          delta: 72.39,
          assignment: 'CH₂'
        }],
        from: 72.38625,
        to: 72.39375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 161.93,
          assignment: 'CH'
        }],
        from: 161.92625,
        to: 161.93375
      }, {
        signals: [{
          delta: 35.22,
          assignment: 'CH₃'
        }],
        from: 35.21625,
        to: 35.223749999999995
      }, {
        signals: [{
          delta: 30.64,
          assignment: 'CH₃'
        }],
        from: 30.63625,
        to: 30.64375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.17,
          assignment: 'CH₂'
        }],
        from: 67.16625,
        to: 67.17375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.63,
          assignment: 'CH₃'
        }],
        from: 58.626250000000006,
        to: 58.63375
      }, {
        signals: [{
          delta: 72.25,
          assignment: 'CH₂'
        }],
        from: 72.24625,
        to: 72.25375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.94,
          assignment: 'CH₃'
        }],
        from: 6.93625,
        to: 6.9437500000000005
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.78,
          assignment: 'CH₃'
        }],
        from: 18.77625,
        to: 18.78375
      }, {
        signals: [{
          delta: 57.81,
          assignment: 'CH₂'
        }],
        from: 57.806250000000006,
        to: 57.81375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 20.46,
          assignment: 'CH₃CO'
        }],
        from: 20.45625,
        to: 20.46375
      }, {
        signals: [{
          delta: 170.02,
          assignment: 'CO'
        }],
        from: 170.01625,
        to: 170.02375
      }, {
        signals: [{
          delta: 60.08,
          assignment: 'CH₂'
        }],
        from: 60.07625,
        to: 60.083749999999995
      }, {
        signals: [{
          delta: 14.23,
          assignment: 'CH₃'
        }],
        from: 14.22625,
        to: 14.23375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 122.92,
          assignment: 'CH₂'
        }],
        from: 122.91625,
        to: 122.92375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.29,
          assignment: 'CH₂'
        }],
        from: 64.28625000000001,
        to: 64.29375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 30.31,
          assignment: 'CH₂'
        }],
        from: 30.30625,
        to: 30.31375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 131.72,
          assignment: 'C'
        }],
        from: 131.71625,
        to: 131.72375
      }, {
        signals: [{
          delta: 16.84,
          assignment: 'CH₃'
        }],
        from: 16.83625,
        to: 16.84375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.34,
          assignment: 'CH₃'
        }],
        from: 14.33625,
        to: 14.34375
      }, {
        signals: [{
          delta: 23.12,
          assignment: 'CH₂(2,5)'
        }],
        from: 23.11625,
        to: 23.12375
      }, {
        signals: [{
          delta: 32.06,
          assignment: 'CH₂(3,4)'
        }],
        from: 32.056250000000006,
        to: 32.06375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 1.99,
          assignment: 'CH₃'
        }],
        from: 1.98625,
        to: 1.99375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.8,
          assignment: 'CH₃'
        }],
        from: 36.79625,
        to: 36.803749999999994
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.57,
          assignment: 'CH(2)'
        }],
        from: 135.56625,
        to: 135.57375
      }, {
        signals: [{
          delta: 122.13,
          assignment: 'CH(4,5)'
        }],
        from: 122.12625,
        to: 122.13374999999999
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.34,
          assignment: 'CH₄'
        }],
        from: -4.34375,
        to: -4.33625
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.9,
          assignment: 'CH₃'
        }],
        from: 49.89625,
        to: 49.903749999999995
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 61.14,
          assignment: 'CH₃'
        }],
        from: 61.136250000000004,
        to: 61.14375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.27,
          assignment: 'CH₃'
        }],
        from: 14.26625,
        to: 14.27375
      }, {
        signals: [{
          delta: 22.79,
          assignment: 'CH₂(2,4)'
        }],
        from: 22.78625,
        to: 22.79375
      }, {
        signals: [{
          delta: 34.54,
          assignment: 'CH₂(3)'
        }],
        from: 34.53625,
        to: 34.543749999999996
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.65,
          assignment: 'CH₃'
        }],
        from: 16.64625,
        to: 16.65375
      }, {
        signals: [{
          delta: 16.63,
          assignment: 'CH₂'
        }],
        from: 16.62625,
        to: 16.63375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.24,
          assignment: 'CH₃'
        }],
        from: 25.23625,
        to: 25.24375
      }, {
        signals: [{
          delta: 64.12,
          assignment: 'CH'
        }],
        from: 64.11625000000001,
        to: 64.12375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.32,
          assignment: 'CH₃'
        }],
        from: 19.31625,
        to: 19.32375
      }, {
        signals: [{
          delta: 115.89,
          assignment: 'CH₂'
        }],
        from: 115.88625,
        to: 115.89375
      }, {
        signals: [{
          delta: 133.61,
          assignment: 'CH'
        }],
        from: 133.60625000000002,
        to: 133.61375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 150.25,
          assignment: 'CH(2,6)'
        }],
        from: 150.24625,
        to: 150.25375
      }, {
        signals: [{
          delta: 123.46,
          assignment: 'CH(3,5)'
        }],
        from: 123.45625,
        to: 123.46374999999999
      }, {
        signals: [{
          delta: 135.17,
          assignment: 'CH(4)'
        }],
        from: 135.16625,
        to: 135.17374999999998
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 117.61,
          assignment: 'CH(2,5)'
        }],
        from: 117.60625,
        to: 117.61375
      }, {
        signals: [{
          delta: 108.15,
          assignment: 'CH(3,4)'
        }],
        from: 108.14625000000001,
        to: 108.15375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 47.12,
          assignment: 'CH₂(2,5)'
        }],
        from: 47.11625,
        to: 47.123749999999994
      }, {
        signals: [{
          delta: 25.75,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.74625,
        to: 25.75375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 1.37,
          assignment: 'CH₃'
        }],
        from: 1.3662500000000002,
        to: 1.37375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 67.75,
          assignment: 'CH₂(2,5)'
        }],
        from: 67.74625,
        to: 67.75375
      }, {
        signals: [{
          delta: 25.79,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.78625,
        to: 25.79375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.37,
          assignment: 'CH₃'
        }],
        from: 21.36625,
        to: 21.37375
      }, {
        signals: [{
          delta: 137.84,
          assignment: 'C(1)'
        }],
        from: 137.83625,
        to: 137.84375
      }, {
        signals: [{
          delta: 129.33,
          assignment: 'CH(2,6)'
        }],
        from: 129.32625000000002,
        to: 129.33375
      }, {
        signals: [{
          delta: 128.51,
          assignment: 'CH(3,5)'
        }],
        from: 128.50625,
        to: 128.51375
      }, {
        signals: [{
          delta: 125.66,
          assignment: 'CH(4)'
        }],
        from: 125.65625,
        to: 125.66375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 12.39,
          assignment: 'CH₃'
        }],
        from: 12.38625,
        to: 12.39375
      }, {
        signals: [{
          delta: 46.82,
          assignment: 'CH₂'
        }],
        from: 46.816250000000004,
        to: 46.82375
      }],
      nucleus: '13C',
      solvent: 'toluene- d₈'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 175.82,
          assignment: 'CO'
        }],
        from: 175.81625,
        to: 175.82375
      }, {
        signals: [{
          delta: 20.37,
          assignment: 'CH₃'
        }],
        from: 20.36625,
        to: 20.37375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 204.43,
          assignment: 'CO'
        }],
        from: 204.42625,
        to: 204.43375
      }, {
        signals: [{
          delta: 30.14,
          assignment: 'CH₃'
        }],
        from: 30.13625,
        to: 30.14375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 116.02,
          assignment: 'CN'
        }],
        from: 116.01625,
        to: 116.02374999999999
      }, {
        signals: [{
          delta: 0.2,
          assignment: 'CH₃'
        }],
        from: 0.19625,
        to: 0.20375000000000001
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 128.62,
          assignment: 'CH'
        }],
        from: 128.61625,
        to: 128.62375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 68.19,
          assignment: '(CH₃)₃C'
        }],
        from: 68.18625,
        to: 68.19375
      }, {
        signals: [{
          delta: 30.47,
          assignment: '(CH₃)₃C'
        }],
        from: 30.46625,
        to: 30.47375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 124.76,
          assignment: 'CO₂'
        }],
        from: 124.75625000000001,
        to: 124.76375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 192.69,
          assignment: 'CS₂'
        }],
        from: 192.68625,
        to: 192.69375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.44,
          assignment: 'CCl₄'
        }],
        from: 96.43625,
        to: 96.44375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 77.79,
          assignment: 'CH'
        }],
        from: 77.78625000000001,
        to: 77.79375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 70.59,
          assignment: 'CH₂'
        }],
        from: 70.58625,
        to: 70.59375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 27.23,
          assignment: 'CH₂'
        }],
        from: 27.22625,
        to: 27.23375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 43.59,
          assignment: 'CH₂'
        }],
        from: 43.58625000000001,
        to: 43.59375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 53.46,
          assignment: 'CH₂'
        }],
        from: 53.456250000000004,
        to: 53.46375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.46,
          assignment: 'CH₃'
        }],
        from: 15.45625,
        to: 15.463750000000001
      }, {
        signals: [{
          delta: 65.94,
          assignment: 'CH₂'
        }],
        from: 65.93625,
        to: 65.94375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.66,
          assignment: 'CH₃'
        }],
        from: 58.65625,
        to: 58.66374999999999
      }, {
        signals: [{
          delta: 70.87,
          assignment: 'CH₂'
        }],
        from: 70.86625000000001,
        to: 70.87375
      }, {
        signals: [{
          delta: 72.35,
          assignment: 'CH₂'
        }],
        from: 72.34625,
        to: 72.35374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 162.13,
          assignment: 'CH'
        }],
        from: 162.12625,
        to: 162.13375
      }, {
        signals: [{
          delta: 35.25,
          assignment: 'CH₃'
        }],
        from: 35.24625,
        to: 35.25375
      }, {
        signals: [{
          delta: 30.72,
          assignment: 'CH₃'
        }],
        from: 30.71625,
        to: 30.72375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.16,
          assignment: 'CH₂'
        }],
        from: 67.15625,
        to: 67.16375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.68,
          assignment: 'CH₃'
        }],
        from: 58.67625,
        to: 58.683749999999996
      }, {
        signals: [{
          delta: 72.21,
          assignment: 'CH₂'
        }],
        from: 72.20625,
        to: 72.21374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.96,
          assignment: 'CH₃'
        }],
        from: 6.95625,
        to: 6.96375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.72,
          assignment: 'CH₃'
        }],
        from: 18.71625,
        to: 18.72375
      }, {
        signals: [{
          delta: 57.86,
          assignment: 'CH₂'
        }],
        from: 57.85625,
        to: 57.863749999999996
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 20.56,
          assignment: 'CH₃CO'
        }],
        from: 20.55625,
        to: 20.56375
      }, {
        signals: [{
          delta: 170.44,
          assignment: 'CO'
        }],
        from: 170.43625,
        to: 170.44375
      }, {
        signals: [{
          delta: 60.21,
          assignment: 'CH₂'
        }],
        from: 60.206250000000004,
        to: 60.21375
      }, {
        signals: [{
          delta: 14.19,
          assignment: 'CH₃'
        }],
        from: 14.18625,
        to: 14.19375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 122.96,
          assignment: 'CH₂'
        }],
        from: 122.95625,
        to: 122.96374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.34,
          assignment: 'CH₂'
        }],
        from: 64.33625,
        to: 64.34375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 30.22,
          assignment: 'CH₂'
        }],
        from: 30.21625,
        to: 30.22375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 131.79,
          assignment: 'C'
        }],
        from: 131.78625,
        to: 131.79375
      }, {
        signals: [{
          delta: 16.95,
          assignment: 'CH₃'
        }],
        from: 16.94625,
        to: 16.95375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.32,
          assignment: 'CH₃'
        }],
        from: 14.31625,
        to: 14.32375
      }, {
        signals: [{
          delta: 23.04,
          assignment: 'CH₂(2,5)'
        }],
        from: 23.03625,
        to: 23.04375
      }, {
        signals: [{
          delta: 31.96,
          assignment: 'CH₂(3,4)'
        }],
        from: 31.95625,
        to: 31.96375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 2.05,
          assignment: 'CH₃'
        }],
        from: 2.0462499999999997,
        to: 2.05375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.88,
          assignment: 'CH₃'
        }],
        from: 36.876250000000006,
        to: 36.88375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.76,
          assignment: 'CH(2)'
        }],
        from: 135.75625,
        to: 135.76375
      }, {
        signals: [{
          delta: 122.16,
          assignment: 'CH(4,5)'
        }],
        from: 122.15625,
        to: 122.16375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.29,
          assignment: 'CH₄'
        }],
        from: -4.29375,
        to: -4.28625
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.97,
          assignment: 'CH₃'
        }],
        from: 49.96625,
        to: 49.973749999999995
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 61.16,
          assignment: 'CH₃'
        }],
        from: 61.15625,
        to: 61.16374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.25,
          assignment: 'CH₃'
        }],
        from: 14.24625,
        to: 14.25375
      }, {
        signals: [{
          delta: 22.72,
          assignment: 'CH₂(2,4)'
        }],
        from: 22.71625,
        to: 22.72375
      }, {
        signals: [{
          delta: 34.45,
          assignment: 'CH₂(3)'
        }],
        from: 34.446250000000006,
        to: 34.45375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.66,
          assignment: 'CH₃'
        }],
        from: 16.65625,
        to: 16.66375
      }, {
        signals: [{
          delta: 16.6,
          assignment: 'CH₂'
        }],
        from: 16.59625,
        to: 16.60375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.18,
          assignment: 'CH₃'
        }],
        from: 25.17625,
        to: 25.18375
      }, {
        signals: [{
          delta: 64.23,
          assignment: 'CH'
        }],
        from: 64.22625000000001,
        to: 64.23375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.38,
          assignment: 'CH₃'
        }],
        from: 19.37625,
        to: 19.38375
      }, {
        signals: [{
          delta: 115.92,
          assignment: 'CH₂'
        }],
        from: 115.91625,
        to: 115.92375
      }, {
        signals: [{
          delta: 133.69,
          assignment: 'CH'
        }],
        from: 133.68625,
        to: 133.69375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 150.27,
          assignment: 'CH(2,6)'
        }],
        from: 150.26625,
        to: 150.27375
      }, {
        signals: [{
          delta: 123.58,
          assignment: 'CH(3,5)'
        }],
        from: 123.57625,
        to: 123.58375
      }, {
        signals: [{
          delta: 135.28,
          assignment: 'CH(4)'
        }],
        from: 135.27625,
        to: 135.28375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 117.78,
          assignment: 'CH(2,5)'
        }],
        from: 117.77625,
        to: 117.78375
      }, {
        signals: [{
          delta: 108.21,
          assignment: 'CH(3,4)'
        }],
        from: 108.20625,
        to: 108.21374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 46.86,
          assignment: 'CH₂(2,5)'
        }],
        from: 46.85625,
        to: 46.863749999999996
      }, {
        signals: [{
          delta: 25.65,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.64625,
        to: 25.65375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 1.38,
          assignment: 'CH₃'
        }],
        from: 1.37625,
        to: 1.3837499999999998
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 67.8,
          assignment: 'CH₂(2,5)'
        }],
        from: 67.79625,
        to: 67.80375
      }, {
        signals: [{
          delta: 25.72,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.71625,
        to: 25.72375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.1,
          assignment: 'CH₃'
        }],
        from: 21.09625,
        to: 21.10375
      }, {
        signals: [{
          delta: 137.91,
          assignment: 'C(1)'
        }],
        from: 137.90625,
        to: 137.91375
      }, {
        signals: [{
          delta: 129.33,
          assignment: 'CH(2,6)'
        }],
        from: 129.32625000000002,
        to: 129.33375
      }, {
        signals: [{
          delta: 128.56,
          assignment: 'CH(3,5)'
        }],
        from: 128.55625,
        to: 128.56375
      }, {
        signals: [{
          delta: 125.68,
          assignment: 'CH(4)'
        }],
        from: 125.67625000000001,
        to: 125.68375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 12.35,
          assignment: 'CH₃'
        }],
        from: 12.34625,
        to: 12.35375
      }, {
        signals: [{
          delta: 46.77,
          assignment: 'CH₂'
        }],
        from: 46.76625000000001,
        to: 46.77375
      }],
      nucleus: '13C',
      solvent: 'C₆D₆'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 175.67,
          assignment: 'CO'
        }],
        from: 175.66625,
        to: 175.67374999999998
      }, {
        signals: [{
          delta: 20.4,
          assignment: 'CH₃'
        }],
        from: 20.39625,
        to: 20.40375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 204.83,
          assignment: 'CO'
        }],
        from: 204.82625000000002,
        to: 204.83375
      }, {
        signals: [{
          delta: 30.12,
          assignment: 'CH₃'
        }],
        from: 30.11625,
        to: 30.12375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 115.93,
          assignment: 'CN'
        }],
        from: 115.92625000000001,
        to: 115.93375
      }, {
        signals: [{
          delta: 0.63,
          assignment: 'CH₃'
        }],
        from: 0.62625,
        to: 0.63375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 128.38,
          assignment: 'CH'
        }],
        from: 128.37625,
        to: 128.38375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 68.19,
          assignment: '(CH₃)₃C'
        }],
        from: 68.18625,
        to: 68.19375
      }, {
        signals: [{
          delta: 31.13,
          assignment: '(CH₃)₃C'
        }],
        from: 31.12625,
        to: 31.13375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 126.08,
          assignment: 'CO₂'
        }],
        from: 126.07625,
        to: 126.08375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 192.49,
          assignment: 'CS₂'
        }],
        from: 192.48625,
        to: 192.49375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.38,
          assignment: 'CCl₄'
        }],
        from: 96.37625,
        to: 96.38374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 77.67,
          assignment: 'CH'
        }],
        from: 77.66625,
        to: 77.67375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 70.55,
          assignment: 'CH₂'
        }],
        from: 70.54625,
        to: 70.55375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 26.99,
          assignment: 'CH₂'
        }],
        from: 26.98625,
        to: 26.99375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 43.6,
          assignment: 'CH₂'
        }],
        from: 43.596250000000005,
        to: 43.60375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 53.54,
          assignment: 'CH₂'
        }],
        from: 53.53625,
        to: 53.543749999999996
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.35,
          assignment: 'CH₃'
        }],
        from: 15.34625,
        to: 15.35375
      }, {
        signals: [{
          delta: 65.79,
          assignment: 'CH₂'
        }],
        from: 65.78625000000001,
        to: 65.79375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.42,
          assignment: 'CH₃'
        }],
        from: 58.416250000000005,
        to: 58.42375
      }, {
        signals: [{
          delta: 70.56,
          assignment: 'CH₂'
        }],
        from: 70.55625,
        to: 70.56375
      }, {
        signals: [{
          delta: 72.07,
          assignment: 'CH₂'
        }],
        from: 72.06625,
        to: 72.07374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 162.01,
          assignment: 'CH'
        }],
        from: 162.00625,
        to: 162.01375
      }, {
        signals: [{
          delta: 35.45,
          assignment: 'CH₃'
        }],
        from: 35.446250000000006,
        to: 35.45375
      }, {
        signals: [{
          delta: 30.71,
          assignment: 'CH₃'
        }],
        from: 30.70625,
        to: 30.71375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 66.95,
          assignment: 'CH₂'
        }],
        from: 66.94625,
        to: 66.95375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.31,
          assignment: 'CH₃'
        }],
        from: 58.306250000000006,
        to: 58.31375
      }, {
        signals: [{
          delta: 71.81,
          assignment: 'CH₂'
        }],
        from: 71.80625,
        to: 71.81375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.91,
          assignment: 'CH₃'
        }],
        from: 6.90625,
        to: 6.91375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.55,
          assignment: 'CH₃'
        }],
        from: 18.54625,
        to: 18.55375
      }, {
        signals: [{
          delta: 57.63,
          assignment: 'CH₂'
        }],
        from: 57.626250000000006,
        to: 57.63375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 20.5,
          assignment: 'CH₃CO'
        }],
        from: 20.49625,
        to: 20.50375
      }, {
        signals: [{
          delta: 170.2,
          assignment: 'CO'
        }],
        from: 170.19625,
        to: 170.20374999999999
      }, {
        signals: [{
          delta: 60.06,
          assignment: 'CH₂'
        }],
        from: 60.056250000000006,
        to: 60.06375
      }, {
        signals: [{
          delta: 14.07,
          assignment: 'CH₃'
        }],
        from: 14.06625,
        to: 14.07375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 122.95,
          assignment: 'CH₂'
        }],
        from: 122.94625,
        to: 122.95375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.03,
          assignment: 'CH₂'
        }],
        from: 64.02625,
        to: 64.03375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 30.11,
          assignment: 'CH₂'
        }],
        from: 30.10625,
        to: 30.11375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 131.54,
          assignment: 'C'
        }],
        from: 131.53625,
        to: 131.54375
      }, {
        signals: [{
          delta: 16.68,
          assignment: 'CH₃'
        }],
        from: 16.67625,
        to: 16.68375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.18,
          assignment: 'CH₃'
        }],
        from: 14.17625,
        to: 14.18375
      }, {
        signals: [{
          delta: 22.86,
          assignment: 'CH₂(2,5)'
        }],
        from: 22.85625,
        to: 22.86375
      }, {
        signals: [{
          delta: 31.77,
          assignment: 'CH₂(3,4)'
        }],
        from: 31.76625,
        to: 31.77375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 1.92,
          assignment: 'CH₃'
        }],
        from: 1.91625,
        to: 1.9237499999999998
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.64,
          assignment: 'CH₃'
        }],
        from: 36.636250000000004,
        to: 36.64375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.5,
          assignment: 'CH(2)'
        }],
        from: 135.49625,
        to: 135.50375
      }, {
        signals: [{
          delta: 121.96,
          assignment: 'CH(4,5)'
        }],
        from: 121.95625,
        to: 121.96374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.33,
          assignment: 'CH₄'
        }],
        from: -4.33375,
        to: -4.32625
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.66,
          assignment: 'CH₃'
        }],
        from: 49.65625,
        to: 49.66374999999999
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 61.68,
          assignment: 'CH₃'
        }],
        from: 61.67625,
        to: 61.683749999999996
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.1,
          assignment: 'CH₃'
        }],
        from: 14.09625,
        to: 14.10375
      }, {
        signals: [{
          delta: 22.54,
          assignment: 'CH₂(2,4)'
        }],
        from: 22.53625,
        to: 22.54375
      }, {
        signals: [{
          delta: 34.26,
          assignment: 'CH₂(3)'
        }],
        from: 34.25625,
        to: 34.263749999999995
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.56,
          assignment: 'CH₃'
        }],
        from: 16.55625,
        to: 16.56375
      }, {
        signals: [{
          delta: 16.48,
          assignment: 'CH₂'
        }],
        from: 16.47625,
        to: 16.48375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.14,
          assignment: 'CH₃'
        }],
        from: 25.13625,
        to: 25.14375
      }, {
        signals: [{
          delta: 64.18,
          assignment: 'CH'
        }],
        from: 64.17625000000001,
        to: 64.18375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.32,
          assignment: 'CH₃'
        }],
        from: 19.31625,
        to: 19.32375
      }, {
        signals: [{
          delta: 115.86,
          assignment: 'CH₂'
        }],
        from: 115.85625,
        to: 115.86375
      }, {
        signals: [{
          delta: 133.57,
          assignment: 'CH'
        }],
        from: 133.56625,
        to: 133.57375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 149.93,
          assignment: 'CH(2,6)'
        }],
        from: 149.92625,
        to: 149.93375
      }, {
        signals: [{
          delta: 123.49,
          assignment: 'CH(3,5)'
        }],
        from: 123.48625,
        to: 123.49374999999999
      }, {
        signals: [{
          delta: 135.32,
          assignment: 'CH(4)'
        }],
        from: 135.31625,
        to: 135.32375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 117.65,
          assignment: 'CH(2,5)'
        }],
        from: 117.64625000000001,
        to: 117.65375
      }, {
        signals: [{
          delta: 108.03,
          assignment: 'CH(3,4)'
        }],
        from: 108.02625,
        to: 108.03375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 46.75,
          assignment: 'CH₂(2,5)'
        }],
        from: 46.74625,
        to: 46.75375
      }, {
        signals: [{
          delta: 25.59,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.58625,
        to: 25.59375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 1.09,
          assignment: 'CH₃'
        }],
        from: 1.0862500000000002,
        to: 1.09375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 67.64,
          assignment: 'CH₂(2,5)'
        }],
        from: 67.63625,
        to: 67.64375
      }, {
        signals: [{
          delta: 25.68,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.67625,
        to: 25.68375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.23,
          assignment: 'CH₃'
        }],
        from: 21.22625,
        to: 21.23375
      }, {
        signals: [{
          delta: 137.65,
          assignment: 'C(1)'
        }],
        from: 137.64625,
        to: 137.65375
      }, {
        signals: [{
          delta: 129.12,
          assignment: 'CH(2,6)'
        }],
        from: 129.11625,
        to: 129.12375
      }, {
        signals: [{
          delta: 128.31,
          assignment: 'CH(3,5)'
        }],
        from: 128.30625,
        to: 128.31375
      }, {
        signals: [{
          delta: 125.43,
          assignment: 'CH(4)'
        }],
        from: 125.42625000000001,
        to: 125.43375
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 11.87,
          assignment: 'CH₃'
        }],
        from: 11.866249999999999,
        to: 11.87375
      }, {
        signals: [{
          delta: 46.36,
          assignment: 'CH₂'
        }],
        from: 46.35625,
        to: 46.363749999999996
      }],
      nucleus: '13C',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 172.31,
          assignment: 'CO'
        }],
        from: 172.30625,
        to: 172.31375
      }, {
        signals: [{
          delta: 20.51,
          assignment: 'CH₃'
        }],
        from: 20.50625,
        to: 20.51375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 205.87,
          assignment: 'CO'
        }],
        from: 205.86625,
        to: 205.87375
      }, {
        signals: [{
          delta: 30.6,
          assignment: 'CH₃'
        }],
        from: 30.59625,
        to: 30.60375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 117.6,
          assignment: 'CN'
        }],
        from: 117.59625,
        to: 117.60374999999999
      }, {
        signals: [{
          delta: 1.12,
          assignment: 'CH₃'
        }],
        from: 1.1162500000000002,
        to: 1.12375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 129.15,
          assignment: 'CH'
        }],
        from: 129.14625,
        to: 129.15375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 68.13,
          assignment: '(CH₃)₃C'
        }],
        from: 68.12625,
        to: 68.13374999999999
      }, {
        signals: [{
          delta: 30.72,
          assignment: '(CH₃)₃C'
        }],
        from: 30.71625,
        to: 30.72375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 125.81,
          assignment: 'CO₂'
        }],
        from: 125.80625,
        to: 125.81375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 193.58,
          assignment: 'CS₂'
        }],
        from: 193.57625000000002,
        to: 193.58375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.65,
          assignment: 'CCl₄'
        }],
        from: 96.64625000000001,
        to: 96.65375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 79.19,
          assignment: 'CH'
        }],
        from: 79.18625,
        to: 79.19375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 71.25,
          assignment: 'CH₂'
        }],
        from: 71.24625,
        to: 71.25375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 27.51,
          assignment: 'CH₂'
        }],
        from: 27.50625,
        to: 27.51375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 45.25,
          assignment: 'CH₂'
        }],
        from: 45.24625,
        to: 45.25375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 54.95,
          assignment: 'CH₂'
        }],
        from: 54.946250000000006,
        to: 54.95375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.78,
          assignment: 'CH₃'
        }],
        from: 15.77625,
        to: 15.78375
      }, {
        signals: [{
          delta: 66.12,
          assignment: 'CH₂'
        }],
        from: 66.11625000000001,
        to: 66.12375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.77,
          assignment: 'CH₃'
        }],
        from: 58.76625000000001,
        to: 58.77375
      }, {
        signals: [{
          delta: 71.03,
          assignment: 'CH₂'
        }],
        from: 71.02625,
        to: 71.03375
      }, {
        signals: [{
          delta: 72.63,
          assignment: 'CH₂'
        }],
        from: 72.62625,
        to: 72.63374999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 162.79,
          assignment: 'CH'
        }],
        from: 162.78625,
        to: 162.79375
      }, {
        signals: [{
          delta: 36.15,
          assignment: 'CH₃'
        }],
        from: 36.14625,
        to: 36.153749999999995
      }, {
        signals: [{
          delta: 31.03,
          assignment: 'CH₃'
        }],
        from: 31.02625,
        to: 31.03375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.6,
          assignment: 'CH₂'
        }],
        from: 67.59625,
        to: 67.60374999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.45,
          assignment: 'CH₃'
        }],
        from: 58.446250000000006,
        to: 58.45375
      }, {
        signals: [{
          delta: 72.47,
          assignment: 'CH₂'
        }],
        from: 72.46625,
        to: 72.47375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.88,
          assignment: 'CH₃'
        }],
        from: 6.87625,
        to: 6.88375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.89,
          assignment: 'CH₃'
        }],
        from: 18.88625,
        to: 18.89375
      }, {
        signals: [{
          delta: 57.72,
          assignment: 'CH₂'
        }],
        from: 57.71625,
        to: 57.723749999999995
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 20.83,
          assignment: 'CH₃CO'
        }],
        from: 20.826249999999998,
        to: 20.83375
      }, {
        signals: [{
          delta: 170.96,
          assignment: 'CO'
        }],
        from: 170.95625,
        to: 170.96375
      }, {
        signals: [{
          delta: 60.56,
          assignment: 'CH₂'
        }],
        from: 60.556250000000006,
        to: 60.56375
      }, {
        signals: [{
          delta: 14.5,
          assignment: 'CH₃'
        }],
        from: 14.49625,
        to: 14.50375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 123.47,
          assignment: 'CH₂'
        }],
        from: 123.46625,
        to: 123.47375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.26,
          assignment: 'CH₂'
        }],
        from: 64.25625000000001,
        to: 64.26375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 132.22,
          assignment: 'C'
        }],
        from: 132.21625,
        to: 132.22375
      }, {
        signals: [{
          delta: 16.86,
          assignment: 'CH₃'
        }],
        from: 16.85625,
        to: 16.86375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.34,
          assignment: 'CH₃'
        }],
        from: 14.33625,
        to: 14.34375
      }, {
        signals: [{
          delta: 23.28,
          assignment: 'CH₂(2,5)'
        }],
        from: 23.27625,
        to: 23.28375
      }, {
        signals: [{
          delta: 32.3,
          assignment: 'CH₂(3,4)'
        }],
        from: 32.29625,
        to: 32.303749999999994
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 2.01,
          assignment: 'CH₃'
        }],
        from: 2.0062499999999996,
        to: 2.01375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 37.04,
          assignment: 'CH₃'
        }],
        from: 37.03625,
        to: 37.043749999999996
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.89,
          assignment: 'CH(2)'
        }],
        from: 135.88625,
        to: 135.89374999999998
      }, {
        signals: [{
          delta: 122.31,
          assignment: 'CH(4,5)'
        }],
        from: 122.30625,
        to: 122.31375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -5.33,
          assignment: 'CH₄'
        }],
        from: -5.33375,
        to: -5.32625
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.77,
          assignment: 'CH₃'
        }],
        from: 49.76625000000001,
        to: 49.77375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 63.21,
          assignment: 'CH₃'
        }],
        from: 63.206250000000004,
        to: 63.21375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.29,
          assignment: 'CH₃'
        }],
        from: 14.286249999999999,
        to: 14.29375
      }, {
        signals: [{
          delta: 22.98,
          assignment: 'CH₂(2,4)'
        }],
        from: 22.97625,
        to: 22.98375
      }, {
        signals: [{
          delta: 34.83,
          assignment: 'CH₂(3)'
        }],
        from: 34.82625,
        to: 34.833749999999995
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.68,
          assignment: 'CH₃'
        }],
        from: 16.67625,
        to: 16.68375
      }, {
        signals: [{
          delta: 16.78,
          assignment: 'CH₂'
        }],
        from: 16.77625,
        to: 16.78375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.67,
          assignment: 'CH₃'
        }],
        from: 25.66625,
        to: 25.673750000000002
      }, {
        signals: [{
          delta: 63.85,
          assignment: 'CH'
        }],
        from: 63.846250000000005,
        to: 63.85375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.42,
          assignment: 'CH₃'
        }],
        from: 19.41625,
        to: 19.423750000000002
      }, {
        signals: [{
          delta: 116.03,
          assignment: 'CH₂'
        }],
        from: 116.02625,
        to: 116.03375
      }, {
        signals: [{
          delta: 134.34,
          assignment: 'CH'
        }],
        from: 134.33625,
        to: 134.34375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 150.67,
          assignment: 'CH(2,6)'
        }],
        from: 150.66625,
        to: 150.67374999999998
      }, {
        signals: [{
          delta: 124.57,
          assignment: 'CH(3,5)'
        }],
        from: 124.56625,
        to: 124.57374999999999
      }, {
        signals: [{
          delta: 136.56,
          assignment: 'CH(4)'
        }],
        from: 136.55625,
        to: 136.56375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 117.98,
          assignment: 'CH(2,5)'
        }],
        from: 117.97625000000001,
        to: 117.98375
      }, {
        signals: [{
          delta: 108.04,
          assignment: 'CH(3,4)'
        }],
        from: 108.03625000000001,
        to: 108.04375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 1.4,
          assignment: 'CH₃'
        }],
        from: 1.39625,
        to: 1.4037499999999998
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 68.07,
          assignment: 'CH₂(2,5)'
        }],
        from: 68.06625,
        to: 68.07374999999999
      }, {
        signals: [{
          delta: 26.15,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.14625,
        to: 26.15375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.46,
          assignment: 'CH₃'
        }],
        from: 21.45625,
        to: 21.46375
      }, {
        signals: [{
          delta: 138.48,
          assignment: 'C(1)'
        }],
        from: 138.47625,
        to: 138.48375
      }, {
        signals: [{
          delta: 129.76,
          assignment: 'CH(2,6)'
        }],
        from: 129.75625,
        to: 129.76375
      }, {
        signals: [{
          delta: 129.03,
          assignment: 'CH(3,5)'
        }],
        from: 129.02625,
        to: 129.03375
      }, {
        signals: [{
          delta: 126.12,
          assignment: 'CH(4)'
        }],
        from: 126.11625000000001,
        to: 126.12375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 12.49,
          assignment: 'CH₃'
        }],
        from: 12.48625,
        to: 12.49375
      }, {
        signals: [{
          delta: 47.07,
          assignment: 'CH₂'
        }],
        from: 47.066250000000004,
        to: 47.07375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 171.93,
          assignment: 'CO'
        }],
        from: 171.92625,
        to: 171.93375
      }, {
        signals: [{
          delta: 20.95,
          assignment: 'CH₃'
        }],
        from: 20.94625,
        to: 20.95375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 206.31,
          assignment: 'CO'
        }],
        from: 206.30625,
        to: 206.31375
      }, {
        signals: [{
          delta: 30.56,
          assignment: 'CH₃'
        }],
        from: 30.55625,
        to: 30.56375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 117.91,
          assignment: 'CN'
        }],
        from: 117.90625,
        to: 117.91375
      }, {
        signals: [{
          delta: 1.03,
          assignment: 'CH₃'
        }],
        from: 1.02625,
        to: 1.03375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 128.3,
          assignment: 'CH'
        }],
        from: 128.29625000000001,
        to: 128.30375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 66.88,
          assignment: '(CH₃)₃C'
        }],
        from: 66.87625,
        to: 66.88374999999999
      }, {
        signals: [{
          delta: 30.38,
          assignment: '(CH₃)₃C'
        }],
        from: 30.37625,
        to: 30.38375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 124.21,
          assignment: 'CO₂'
        }],
        from: 124.20625,
        to: 124.21374999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 192.63,
          assignment: 'CS₂'
        }],
        from: 192.62625,
        to: 192.63375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 95.44,
          assignment: 'CCl₄'
        }],
        from: 95.43625,
        to: 95.44375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 79.16,
          assignment: 'CH'
        }],
        from: 79.15625,
        to: 79.16375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 69.85,
          assignment: 'CH₂'
        }],
        from: 69.84625,
        to: 69.85374999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 26.33,
          assignment: 'CH₂'
        }],
        from: 26.326249999999998,
        to: 26.33375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 45.02,
          assignment: 'CH₂'
        }],
        from: 45.01625000000001,
        to: 45.02375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 54.84,
          assignment: 'CH₂'
        }],
        from: 54.83625000000001,
        to: 54.84375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.12,
          assignment: 'CH₃'
        }],
        from: 15.116249999999999,
        to: 15.12375
      }, {
        signals: [{
          delta: 62.05,
          assignment: 'CH₂'
        }],
        from: 62.04625,
        to: 62.053749999999994
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 57.98,
          assignment: 'CH₃'
        }],
        from: 57.97625,
        to: 57.98374999999999
      }, {
        signals: [{
          delta: 69.54,
          assignment: 'CH₂'
        }],
        from: 69.53625000000001,
        to: 69.54375
      }, {
        signals: [{
          delta: 71.25,
          assignment: 'CH₂'
        }],
        from: 71.24625,
        to: 71.25375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 162.29,
          assignment: 'CH'
        }],
        from: 162.28625,
        to: 162.29375
      }, {
        signals: [{
          delta: 35.73,
          assignment: 'CH₃'
        }],
        from: 35.72625,
        to: 35.73374999999999
      }, {
        signals: [{
          delta: 30.73,
          assignment: 'CH₃'
        }],
        from: 30.72625,
        to: 30.73375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 66.36,
          assignment: 'CH₂'
        }],
        from: 66.35625,
        to: 66.36375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.03,
          assignment: 'CH₃'
        }],
        from: 58.026250000000005,
        to: 58.03375
      }, {
        signals: [{
          delta: 71.17,
          assignment: 'CH₂'
        }],
        from: 71.16625,
        to: 71.17375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.61,
          assignment: 'CH₃'
        }],
        from: 6.60625,
        to: 6.6137500000000005
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.51,
          assignment: 'CH₃'
        }],
        from: 18.50625,
        to: 18.51375
      }, {
        signals: [{
          delta: 56.07,
          assignment: 'CH₂'
        }],
        from: 56.066250000000004,
        to: 56.07375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 20.68,
          assignment: 'CH₃CO'
        }],
        from: 20.67625,
        to: 20.68375
      }, {
        signals: [{
          delta: 170.31,
          assignment: 'CO'
        }],
        from: 170.30625,
        to: 170.31375
      }, {
        signals: [{
          delta: 59.74,
          assignment: 'CH₂'
        }],
        from: 59.736250000000005,
        to: 59.74375
      }, {
        signals: [{
          delta: 14.4,
          assignment: 'CH₃'
        }],
        from: 14.39625,
        to: 14.40375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 123.52,
          assignment: 'CH₂'
        }],
        from: 123.51625,
        to: 123.52374999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 62.76,
          assignment: 'CH₂'
        }],
        from: 62.75625,
        to: 62.763749999999995
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 131.1,
          assignment: 'C'
        }],
        from: 131.09625,
        to: 131.10375
      }, {
        signals: [{
          delta: 16.6,
          assignment: 'CH₃'
        }],
        from: 16.59625,
        to: 16.60375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 13.88,
          assignment: 'CH₃'
        }],
        from: 13.87625,
        to: 13.883750000000001
      }, {
        signals: [{
          delta: 22.05,
          assignment: 'CH₂(2,5)'
        }],
        from: 22.04625,
        to: 22.05375
      }, {
        signals: [{
          delta: 30.95,
          assignment: 'CH₂(3,4)'
        }],
        from: 30.94625,
        to: 30.95375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 1.96,
          assignment: 'CH₃'
        }],
        from: 1.95625,
        to: 1.9637499999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.42,
          assignment: 'CH₃'
        }],
        from: 36.416250000000005,
        to: 36.42375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 135.15,
          assignment: 'CH(2)'
        }],
        from: 135.14625,
        to: 135.15375
      }, {
        signals: [{
          delta: 121.55,
          assignment: 'CH(4,5)'
        }],
        from: 121.54625,
        to: 121.55375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.01,
          assignment: 'CH₄'
        }],
        from: -4.01375,
        to: -4.00625
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 48.59,
          assignment: 'CH₃'
        }],
        from: 48.58625000000001,
        to: 48.59375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 63.28,
          assignment: 'CH₃'
        }],
        from: 63.276250000000005,
        to: 63.28375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 13.28,
          assignment: 'CH₃'
        }],
        from: 13.27625,
        to: 13.28375
      }, {
        signals: [{
          delta: 21.7,
          assignment: 'CH₂(2,4)'
        }],
        from: 21.69625,
        to: 21.70375
      }, {
        signals: [{
          delta: 33.48,
          assignment: 'CH₂(3)'
        }],
        from: 33.47625,
        to: 33.48374999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.34,
          assignment: 'CH₃'
        }],
        from: 16.33625,
        to: 16.34375
      }, {
        signals: [{
          delta: 15.67,
          assignment: 'CH₂'
        }],
        from: 15.66625,
        to: 15.67375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.43,
          assignment: 'CH₃'
        }],
        from: 25.42625,
        to: 25.43375
      }, {
        signals: [{
          delta: 64.92,
          assignment: 'CH'
        }],
        from: 64.91625,
        to: 64.92375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.2,
          assignment: 'CH₃'
        }],
        from: 19.19625,
        to: 19.20375
      }, {
        signals: [{
          delta: 116.07,
          assignment: 'CH₂'
        }],
        from: 116.06625,
        to: 116.07374999999999
      }, {
        signals: [{
          delta: 133.55,
          assignment: 'CH'
        }],
        from: 133.54625000000001,
        to: 133.55375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 149.58,
          assignment: 'CH(2,6)'
        }],
        from: 149.57625000000002,
        to: 149.58375
      }, {
        signals: [{
          delta: 123.84,
          assignment: 'CH(3,5)'
        }],
        from: 123.83625,
        to: 123.84375
      }, {
        signals: [{
          delta: 136.05,
          assignment: 'CH(4)'
        }],
        from: 136.04625000000001,
        to: 136.05375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 117.32,
          assignment: 'CH(2,5)'
        }],
        from: 117.31625,
        to: 117.32374999999999
      }, {
        signals: [{
          delta: 107.07,
          assignment: 'CH(3,4)'
        }],
        from: 107.06625,
        to: 107.07374999999999
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 46.51,
          assignment: 'CH₂(2,5)'
        }],
        from: 46.50625,
        to: 46.513749999999995
      }, {
        signals: [{
          delta: 25.26,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.25625,
        to: 25.26375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 67.03,
          assignment: 'CH₂(2,5)'
        }],
        from: 67.02625,
        to: 67.03375
      }, {
        signals: [{
          delta: 25.14,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.13625,
        to: 25.14375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 20.99,
          assignment: 'CH₃'
        }],
        from: 20.98625,
        to: 20.99375
      }, {
        signals: [{
          delta: 137.35,
          assignment: 'C(1)'
        }],
        from: 137.34625,
        to: 137.35375
      }, {
        signals: [{
          delta: 128.88,
          assignment: 'CH(2,6)'
        }],
        from: 128.87625,
        to: 128.88375
      }, {
        signals: [{
          delta: 128.18,
          assignment: 'CH(3,5)'
        }],
        from: 128.17625,
        to: 128.18375
      }, {
        signals: [{
          delta: 125.29,
          assignment: 'CH(4)'
        }],
        from: 125.28625000000001,
        to: 125.29375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 11.74,
          assignment: 'CH₃'
        }],
        from: 11.73625,
        to: 11.74375
      }, {
        signals: [{
          delta: 45.74,
          assignment: 'CH₂'
        }],
        from: 45.736250000000005,
        to: 45.74375
      }],
      nucleus: '13C',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 173.21,
          assignment: 'CO'
        }],
        from: 173.20625,
        to: 173.21375
      }, {
        signals: [{
          delta: 20.73,
          assignment: 'CH₃'
        }],
        from: 20.72625,
        to: 20.73375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 207.43,
          assignment: 'CO'
        }],
        from: 207.42625,
        to: 207.43375
      }, {
        signals: [{
          delta: 30.91,
          assignment: 'CH₃'
        }],
        from: 30.90625,
        to: 30.91375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 118.26,
          assignment: 'CN'
        }],
        from: 118.25625000000001,
        to: 118.26375
      }, {
        signals: [{
          delta: 1.79,
          assignment: 'CH₃'
        }],
        from: 1.7862500000000001,
        to: 1.79375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 129.32,
          assignment: 'CH'
        }],
        from: 129.31625,
        to: 129.32375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 68.74,
          assignment: '(CH₃)₃C'
        }],
        from: 68.73625,
        to: 68.74374999999999
      }, {
        signals: [{
          delta: 30.68,
          assignment: '(CH₃)₃C'
        }],
        from: 30.67625,
        to: 30.68375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 125.89,
          assignment: 'CO₂'
        }],
        from: 125.88625,
        to: 125.89375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 193.6,
          assignment: 'CS₂'
        }],
        from: 193.59625,
        to: 193.60375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.68,
          assignment: 'CCl₄'
        }],
        from: 96.67625000000001,
        to: 96.68375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 79.17,
          assignment: 'CH'
        }],
        from: 79.16625,
        to: 79.17375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 71.22,
          assignment: 'CH₂'
        }],
        from: 71.21625,
        to: 71.22375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 27.63,
          assignment: 'CH₂'
        }],
        from: 27.62625,
        to: 27.63375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 45.54,
          assignment: 'CH₂'
        }],
        from: 45.53625,
        to: 45.543749999999996
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 55.32,
          assignment: 'CH₂'
        }],
        from: 55.316250000000004,
        to: 55.32375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.63,
          assignment: 'CH₃'
        }],
        from: 15.62625,
        to: 15.633750000000001
      }, {
        signals: [{
          delta: 66.32,
          assignment: 'CH₂'
        }],
        from: 66.31625,
        to: 66.32374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.9,
          assignment: 'CH₃'
        }],
        from: 58.89625,
        to: 58.903749999999995
      }, {
        signals: [{
          delta: 70.99,
          assignment: 'CH₂'
        }],
        from: 70.98625,
        to: 70.99374999999999
      }, {
        signals: [{
          delta: 72.63,
          assignment: 'CH₂'
        }],
        from: 72.62625,
        to: 72.63374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 163.31,
          assignment: 'CH'
        }],
        from: 163.30625,
        to: 163.31375
      }, {
        signals: [{
          delta: 36.57,
          assignment: 'CH₃'
        }],
        from: 36.566250000000004,
        to: 36.57375
      }, {
        signals: [{
          delta: 31.32,
          assignment: 'CH₃'
        }],
        from: 31.31625,
        to: 31.32375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.72,
          assignment: 'CH₂'
        }],
        from: 67.71625,
        to: 67.72375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.89,
          assignment: 'CH₃'
        }],
        from: 58.886250000000004,
        to: 58.89375
      }, {
        signals: [{
          delta: 72.47,
          assignment: 'CH₂'
        }],
        from: 72.46625,
        to: 72.47375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.99,
          assignment: 'CH₃'
        }],
        from: 6.98625,
        to: 6.99375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.8,
          assignment: 'CH₃'
        }],
        from: 18.79625,
        to: 18.80375
      }, {
        signals: [{
          delta: 57.96,
          assignment: 'CH₂'
        }],
        from: 57.956250000000004,
        to: 57.96375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 21.16,
          assignment: 'CH₃CO'
        }],
        from: 21.15625,
        to: 21.16375
      }, {
        signals: [{
          delta: 171.68,
          assignment: 'CO'
        }],
        from: 171.67625,
        to: 171.68375
      }, {
        signals: [{
          delta: 60.98,
          assignment: 'CH₂'
        }],
        from: 60.97625,
        to: 60.98374999999999
      }, {
        signals: [{
          delta: 14.54,
          assignment: 'CH₃'
        }],
        from: 14.536249999999999,
        to: 14.54375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 123.69,
          assignment: 'CH₂'
        }],
        from: 123.68625,
        to: 123.69375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.22,
          assignment: 'CH₂'
        }],
        from: 64.21625,
        to: 64.22375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 132.61,
          assignment: 'C'
        }],
        from: 132.60625000000002,
        to: 132.61375
      }, {
        signals: [{
          delta: 16.94,
          assignment: 'CH₃'
        }],
        from: 16.93625,
        to: 16.94375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.43,
          assignment: 'CH₃'
        }],
        from: 14.42625,
        to: 14.43375
      }, {
        signals: [{
          delta: 23.4,
          assignment: 'CH₂(2,5)'
        }],
        from: 23.39625,
        to: 23.40375
      }, {
        signals: [{
          delta: 32.36,
          assignment: 'CH₂(3,4)'
        }],
        from: 32.35625,
        to: 32.363749999999996
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 2.07,
          assignment: 'CH₃'
        }],
        from: 2.0662499999999997,
        to: 2.07375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 37.1,
          assignment: 'CH₃'
        }],
        from: 37.096250000000005,
        to: 37.10375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 136.33,
          assignment: 'CH(2)'
        }],
        from: 136.32625000000002,
        to: 136.33375
      }, {
        signals: [{
          delta: 122.78,
          assignment: 'CH(4,5)'
        }],
        from: 122.77625,
        to: 122.78375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.61,
          assignment: 'CH₄'
        }],
        from: -4.6137500000000005,
        to: -4.60625
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.9,
          assignment: 'CH₃'
        }],
        from: 49.89625,
        to: 49.903749999999995
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 63.66,
          assignment: 'CH₃'
        }],
        from: 63.65625,
        to: 63.66374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.37,
          assignment: 'CH₃'
        }],
        from: 14.366249999999999,
        to: 14.37375
      }, {
        signals: [{
          delta: 23.08,
          assignment: 'CH₂(2,4)'
        }],
        from: 23.076249999999998,
        to: 23.08375
      }, {
        signals: [{
          delta: 34.89,
          assignment: 'CH₂(3)'
        }],
        from: 34.886250000000004,
        to: 34.89375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.73,
          assignment: 'CH₃'
        }],
        from: 16.72625,
        to: 16.73375
      }, {
        signals: [{
          delta: 16.91,
          assignment: 'CH₂'
        }],
        from: 16.90625,
        to: 16.91375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.55,
          assignment: 'CH₃'
        }],
        from: 25.54625,
        to: 25.55375
      }, {
        signals: [{
          delta: 64.3,
          assignment: 'CH'
        }],
        from: 64.29625,
        to: 64.30375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.48,
          assignment: 'CH₃'
        }],
        from: 19.47625,
        to: 19.48375
      }, {
        signals: [{
          delta: 116.12,
          assignment: 'CH₂'
        }],
        from: 116.11625000000001,
        to: 116.12375
      }, {
        signals: [{
          delta: 134.78,
          assignment: 'CH'
        }],
        from: 134.77625,
        to: 134.78375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 150.76,
          assignment: 'CH(2,6)'
        }],
        from: 150.75625,
        to: 150.76375
      }, {
        signals: [{
          delta: 127.76,
          assignment: 'CH(3,5)'
        }],
        from: 127.75625000000001,
        to: 127.76375
      }, {
        signals: [{
          delta: 136.89,
          assignment: 'CH(4)'
        }],
        from: 136.88625,
        to: 136.89374999999998
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 118.47,
          assignment: 'CH(2,5)'
        }],
        from: 118.46625,
        to: 118.47375
      }, {
        signals: [{
          delta: 108.31,
          assignment: 'CH(3,4)'
        }],
        from: 108.30625,
        to: 108.31375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 47.57,
          assignment: 'CH₂(2,5)'
        }],
        from: 47.566250000000004,
        to: 47.57375
      }, {
        signals: [{
          delta: 26.34,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.33625,
        to: 26.34375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 68.33,
          assignment: 'CH₂(2,5)'
        }],
        from: 68.32625,
        to: 68.33375
      }, {
        signals: [{
          delta: 26.27,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.26625,
        to: 26.27375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.5,
          assignment: 'CH₃'
        }],
        from: 21.49625,
        to: 21.50375
      }, {
        signals: [{
          delta: 138.9,
          assignment: 'C(1)'
        }],
        from: 138.89625,
        to: 138.90375
      }, {
        signals: [{
          delta: 129.94,
          assignment: 'CH(2,6)'
        }],
        from: 129.93625,
        to: 129.94375
      }, {
        signals: [{
          delta: 129.23,
          assignment: 'CH(3,5)'
        }],
        from: 129.22625,
        to: 129.23375
      }, {
        signals: [{
          delta: 126.28,
          assignment: 'CH(4)'
        }],
        from: 126.27625,
        to: 126.28375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 12.38,
          assignment: 'CH₃'
        }],
        from: 12.37625,
        to: 12.383750000000001
      }, {
        signals: [{
          delta: 47.1,
          assignment: 'CH₂'
        }],
        from: 47.096250000000005,
        to: 47.10375
      }],
      nucleus: '13C',
      solvent: 'CD₃CN'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 177.96,
          assignment: 'CO'
        }],
        from: 177.95625,
        to: 177.96375
      }, {
        signals: [{
          delta: 20.91,
          assignment: 'CH₃'
        }],
        from: 20.90625,
        to: 20.91375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 32.35,
          assignment: 'CO'
        }],
        from: 32.346250000000005,
        to: 32.35375
      }, {
        signals: [{
          delta: 214.98,
          assignment: 'CH₃'
        }],
        from: 214.97625,
        to: 214.98375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 118.95,
          assignment: 'CN'
        }],
        from: 118.94625,
        to: 118.95375
      }, {
        signals: [{
          delta: 1,
          assignment: 'CH₃'
        }],
        from: 0.99625,
        to: 1.00375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 129.84,
          assignment: 'CH'
        }],
        from: 129.83625,
        to: 129.84375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 72.35,
          assignment: '(CH₃)₃C'
        }],
        from: 72.34625,
        to: 72.35374999999999
      }, {
        signals: [{
          delta: 31.07,
          assignment: '(CH₃)₃C'
        }],
        from: 31.06625,
        to: 31.07375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 126.92,
          assignment: 'CO₂'
        }],
        from: 126.91625,
        to: 126.92375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 196.26,
          assignment: 'CS₂'
        }],
        from: 196.25625,
        to: 196.26375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 97.74,
          assignment: 'CCl₄'
        }],
        from: 97.73625,
        to: 97.74374999999999
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 78.83,
          assignment: 'CH'
        }],
        from: 78.82625,
        to: 78.83375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 70.8,
          assignment: 'CH₂'
        }],
        from: 70.79625,
        to: 70.80375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 28.34,
          assignment: 'CH₂'
        }],
        from: 28.33625,
        to: 28.34375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 45.28,
          assignment: 'CH₂'
        }],
        from: 45.276250000000005,
        to: 45.28375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 54.46,
          assignment: 'CH₂'
        }],
        from: 54.456250000000004,
        to: 54.46375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.33,
          assignment: 'CH₃'
        }],
        from: 15.32625,
        to: 15.33375
      }, {
        signals: [{
          delta: 67.55,
          assignment: 'CH₂'
        }],
        from: 67.54625,
        to: 67.55375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 59.4,
          assignment: 'CH₃'
        }],
        from: 59.39625,
        to: 59.403749999999995
      }, {
        signals: [{
          delta: 73.05,
          assignment: 'CH₂'
        }],
        from: 73.04625,
        to: 73.05375
      }, {
        signals: [{
          delta: 71.33,
          assignment: 'CH₂'
        }],
        from: 71.32625,
        to: 71.33375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 166.01,
          assignment: 'CH'
        }],
        from: 166.00625,
        to: 166.01375
      }, {
        signals: [{
          delta: 37.76,
          assignment: 'CH₃'
        }],
        from: 37.75625,
        to: 37.763749999999995
      }, {
        signals: [{
          delta: 30.96,
          assignment: 'CH₃'
        }],
        from: 30.95625,
        to: 30.96375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 68.52,
          assignment: 'CH₂'
        }],
        from: 68.51625,
        to: 68.52374999999999
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 59.52,
          assignment: 'CH₃'
        }],
        from: 59.51625000000001,
        to: 59.52375
      }, {
        signals: [{
          delta: 72.87,
          assignment: 'CH₂'
        }],
        from: 72.86625000000001,
        to: 72.87375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 7.01,
          assignment: 'CH₃'
        }],
        from: 7.00625,
        to: 7.01375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.11,
          assignment: 'CH₃'
        }],
        from: 18.10625,
        to: 18.11375
      }, {
        signals: [{
          delta: 59.68,
          assignment: 'CH₂'
        }],
        from: 59.67625,
        to: 59.683749999999996
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 21.18,
          assignment: 'CH₃CO'
        }],
        from: 21.17625,
        to: 21.18375
      }, {
        signals: [{
          delta: 175.55,
          assignment: 'CO'
        }],
        from: 175.54625000000001,
        to: 175.55375
      }, {
        signals: [{
          delta: 62.7,
          assignment: 'CH₂'
        }],
        from: 62.696250000000006,
        to: 62.70375
      }, {
        signals: [{
          delta: 14.36,
          assignment: 'CH₃'
        }],
        from: 14.35625,
        to: 14.36375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 124.08,
          assignment: 'CH₂'
        }],
        from: 124.07625,
        to: 124.08375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.87,
          assignment: 'CH₂'
        }],
        from: 64.86625000000001,
        to: 64.87375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 134.04,
          assignment: 'C'
        }],
        from: 134.03625,
        to: 134.04375
      }, {
        signals: [{
          delta: 17.04,
          assignment: 'CH₃'
        }],
        from: 17.03625,
        to: 17.04375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.63,
          assignment: 'CH₃'
        }],
        from: 14.62625,
        to: 14.633750000000001
      }, {
        signals: [{
          delta: 24.06,
          assignment: 'CH₂(2,5)'
        }],
        from: 24.05625,
        to: 24.06375
      }, {
        signals: [{
          delta: 33.17,
          assignment: 'CH₂(3,4)'
        }],
        from: 33.166250000000005,
        to: 33.17375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 2.09,
          assignment: 'CH₃'
        }],
        from: 2.0862499999999997,
        to: 2.09375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 37.21,
          assignment: 'CH₃'
        }],
        from: 37.206250000000004,
        to: 37.21375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 136.58,
          assignment: 'CH(2)'
        }],
        from: 136.57625000000002,
        to: 136.58375
      }, {
        signals: [{
          delta: 122.93,
          assignment: 'CH(4,5)'
        }],
        from: 122.92625000000001,
        to: 122.93375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -5.88,
          assignment: 'CH₄'
        }],
        from: -5.88375,
        to: -5.87625
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 50.67,
          assignment: 'CH₃'
        }],
        from: 50.666250000000005,
        to: 50.67375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 63.17,
          assignment: 'CH₃'
        }],
        from: 63.166250000000005,
        to: 63.17375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.54,
          assignment: 'CH₃'
        }],
        from: 14.536249999999999,
        to: 14.54375
      }, {
        signals: [{
          delta: 23.75,
          assignment: 'CH₂(2,4)'
        }],
        from: 23.74625,
        to: 23.75375
      }, {
        signals: [{
          delta: 35.76,
          assignment: 'CH₂(3)'
        }],
        from: 35.75625,
        to: 35.763749999999995
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.93,
          assignment: 'CH₃'
        }],
        from: 16.92625,
        to: 16.93375
      }, {
        signals: [{
          delta: 17.46,
          assignment: 'CH₂'
        }],
        from: 17.45625,
        to: 17.46375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.21,
          assignment: 'CH₃'
        }],
        from: 25.20625,
        to: 25.21375
      }, {
        signals: [{
          delta: 66.69,
          assignment: 'CH'
        }],
        from: 66.68625,
        to: 66.69375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.63,
          assignment: 'CH₃'
        }],
        from: 19.62625,
        to: 19.63375
      }, {
        signals: [{
          delta: 116.38,
          assignment: 'CH₂'
        }],
        from: 116.37625,
        to: 116.38374999999999
      }, {
        signals: [{
          delta: 136,
          assignment: 'CH'
        }],
        from: 135.99625,
        to: 136.00375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 149.76,
          assignment: 'CH(2,6)'
        }],
        from: 149.75625,
        to: 149.76375
      }, {
        signals: [{
          delta: 126.27,
          assignment: 'CH(3,5)'
        }],
        from: 126.26625,
        to: 126.27374999999999
      }, {
        signals: [{
          delta: 139.62,
          assignment: 'CH(4)'
        }],
        from: 139.61625,
        to: 139.62375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 119.61,
          assignment: 'CH(2,5)'
        }],
        from: 119.60625,
        to: 119.61375
      }, {
        signals: [{
          delta: 108.85,
          assignment: 'CH(3,4)'
        }],
        from: 108.84625,
        to: 108.85374999999999
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 47.43,
          assignment: 'CH₂(2,5)'
        }],
        from: 47.42625,
        to: 47.433749999999996
      }, {
        signals: [{
          delta: 25.73,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.72625,
        to: 25.73375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 2.87,
          assignment: 'CH₃'
        }],
        from: 2.86625,
        to: 2.8737500000000002
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 69.53,
          assignment: 'CH₂(2,5)'
        }],
        from: 69.52625,
        to: 69.53375
      }, {
        signals: [{
          delta: 26.69,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.68625,
        to: 26.69375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.62,
          assignment: 'CH₃'
        }],
        from: 21.61625,
        to: 21.62375
      }, {
        signals: [{
          delta: 139.92,
          assignment: 'C(1)'
        }],
        from: 139.91625,
        to: 139.92374999999998
      }, {
        signals: [{
          delta: 130.58,
          assignment: 'CH(2,6)'
        }],
        from: 130.57625000000002,
        to: 130.58375
      }, {
        signals: [{
          delta: 129.79,
          assignment: 'CH(3,5)'
        }],
        from: 129.78625,
        to: 129.79375
      }, {
        signals: [{
          delta: 126.82,
          assignment: 'CH(4)'
        }],
        from: 126.81625,
        to: 126.82374999999999
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 9.51,
          assignment: 'CH₃'
        }],
        from: 9.50625,
        to: 9.51375
      }, {
        signals: [{
          delta: 48.45,
          assignment: 'CH₂'
        }],
        from: 48.446250000000006,
        to: 48.45375
      }],
      nucleus: '13C',
      solvent: 'TFE-d₃'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 175.11,
          assignment: 'CO'
        }],
        from: 175.10625000000002,
        to: 175.11375
      }, {
        signals: [{
          delta: 20.56,
          assignment: 'CH₃'
        }],
        from: 20.55625,
        to: 20.56375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 209.67,
          assignment: 'CO'
        }],
        from: 209.66625,
        to: 209.67374999999998
      }, {
        signals: [{
          delta: 30.67,
          assignment: 'CH₃'
        }],
        from: 30.66625,
        to: 30.673750000000002
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 118.06,
          assignment: 'CN'
        }],
        from: 118.05625,
        to: 118.06375
      }, {
        signals: [{
          delta: 0.85,
          assignment: 'CH₃'
        }],
        from: 0.84625,
        to: 0.85375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          delta: 129.34,
          assignment: 'CH'
        }],
        from: 129.33625,
        to: 129.34375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 69.4,
          assignment: '(CH₃)₃C'
        }],
        from: 69.39625000000001,
        to: 69.40375
      }, {
        signals: [{
          delta: 30.91,
          assignment: '(CH₃)₃C'
        }],
        from: 30.90625,
        to: 30.91375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [{
        signals: [{
          delta: 126.31,
          assignment: 'CO₂'
        }],
        from: 126.30625,
        to: 126.31375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 193.82,
          assignment: 'CS₂'
        }],
        from: 193.81625,
        to: 193.82375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 97.21,
          assignment: 'CCl₄'
        }],
        from: 97.20625,
        to: 97.21374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 79.44,
          assignment: 'CH'
        }],
        from: 79.43625,
        to: 79.44375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 71.47,
          assignment: 'CH₂'
        }],
        from: 71.46625,
        to: 71.47375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          delta: 27.96,
          assignment: 'CH₂'
        }],
        from: 27.95625,
        to: 27.96375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          delta: 45.11,
          assignment: 'CH₂'
        }],
        from: 45.10625,
        to: 45.113749999999996
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          delta: 54.78,
          assignment: 'CH₂'
        }],
        from: 54.776250000000005,
        to: 54.78375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 15.46,
          assignment: 'CH₃'
        }],
        from: 15.45625,
        to: 15.463750000000001
      }, {
        signals: [{
          delta: 66.88,
          assignment: 'CH₂'
        }],
        from: 66.87625,
        to: 66.88374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 59.06,
          assignment: 'CH₃'
        }],
        from: 59.056250000000006,
        to: 59.06375
      }, {
        signals: [{
          delta: 71.33,
          assignment: 'CH₂'
        }],
        from: 71.32625,
        to: 71.33375
      }, {
        signals: [{
          delta: 72.92,
          assignment: 'CH₂'
        }],
        from: 72.91625,
        to: 72.92375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 164.73,
          assignment: 'CH'
        }],
        from: 164.72625,
        to: 164.73375
      }, {
        signals: [{
          delta: 36.89,
          assignment: 'CH₃'
        }],
        from: 36.886250000000004,
        to: 36.89375
      }, {
        signals: [{
          delta: 31.61,
          assignment: 'CH₃'
        }],
        from: 31.60625,
        to: 31.61375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 68.11,
          assignment: 'CH₂'
        }],
        from: 68.10625,
        to: 68.11375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 59.06,
          assignment: 'CH₃'
        }],
        from: 59.056250000000006,
        to: 59.06375
      }, {
        signals: [{
          delta: 72.72,
          assignment: 'CH₂'
        }],
        from: 72.71625,
        to: 72.72375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          delta: 6.98,
          assignment: 'CH₃'
        }],
        from: 6.97625,
        to: 6.983750000000001
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 18.4,
          assignment: 'CH₃'
        }],
        from: 18.39625,
        to: 18.40375
      }, {
        signals: [{
          delta: 58.26,
          assignment: 'CH₂'
        }],
        from: 58.25625,
        to: 58.263749999999995
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 20.88,
          assignment: 'CH₃CO'
        }],
        from: 20.87625,
        to: 20.88375
      }, {
        signals: [{
          delta: 172.89,
          assignment: 'CO'
        }],
        from: 172.88625,
        to: 172.89374999999998
      }, {
        signals: [{
          delta: 61.5,
          assignment: 'CH₂'
        }],
        from: 61.49625,
        to: 61.50375
      }, {
        signals: [{
          delta: 14.49,
          assignment: 'CH₃'
        }],
        from: 14.48625,
        to: 14.49375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          delta: 123.46,
          assignment: 'CH₂'
        }],
        from: 123.45625,
        to: 123.46374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 64.3,
          assignment: 'CH₂'
        }],
        from: 64.29625,
        to: 64.30375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          delta: 132.53,
          assignment: 'C'
        }],
        from: 132.52625,
        to: 132.53375
      }, {
        signals: [{
          delta: 16.9,
          assignment: 'CH₃'
        }],
        from: 16.89625,
        to: 16.90375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          delta: 14.45,
          assignment: 'CH₃'
        }],
        from: 14.44625,
        to: 14.45375
      }, {
        signals: [{
          delta: 23.68,
          assignment: 'CH₂(2,5)'
        }],
        from: 23.67625,
        to: 23.68375
      }, {
        signals: [{
          delta: 32.73,
          assignment: 'CH₂(3,4)'
        }],
        from: 32.72625,
        to: 32.73374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 1.99,
          assignment: 'CH₃'
        }],
        from: 1.98625,
        to: 1.99375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 37,
          assignment: 'CH₃'
        }],
        from: 36.99625,
        to: 37.00375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 136.31,
          assignment: 'CH(2)'
        }],
        from: 136.30625,
        to: 136.31375
      }, {
        signals: [{
          delta: 122.6,
          assignment: 'CH(4,5)'
        }],
        from: 122.59625,
        to: 122.60374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          delta: -4.9,
          assignment: 'CH₄'
        }],
        from: -4.9037500000000005,
        to: -4.89625
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.86,
          assignment: 'CH₃'
        }],
        from: 49.85625,
        to: 49.863749999999996
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 63.08,
          assignment: 'CH₃'
        }],
        from: 63.07625,
        to: 63.083749999999995
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          delta: 14.39,
          assignment: 'CH₃'
        }],
        from: 14.38625,
        to: 14.39375
      }, {
        signals: [{
          delta: 23.38,
          assignment: 'CH₂(2,4)'
        }],
        from: 23.37625,
        to: 23.38375
      }, {
        signals: [{
          delta: 35.3,
          assignment: 'CH₂(3)'
        }],
        from: 35.29625,
        to: 35.303749999999994
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          delta: 16.8,
          assignment: 'CH₃'
        }],
        from: 16.79625,
        to: 16.80375
      }, {
        signals: [{
          delta: 17.19,
          assignment: 'CH₂'
        }],
        from: 17.18625,
        to: 17.19375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 25.27,
          assignment: 'CH₃'
        }],
        from: 25.26625,
        to: 25.27375
      }, {
        signals: [{
          delta: 64.71,
          assignment: 'CH'
        }],
        from: 64.70625,
        to: 64.71374999999999
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          delta: 19.5,
          assignment: 'CH₃'
        }],
        from: 19.49625,
        to: 19.50375
      }, {
        signals: [{
          delta: 116.04,
          assignment: 'CH₂'
        }],
        from: 116.03625000000001,
        to: 116.04375
      }, {
        signals: [{
          delta: 134.61,
          assignment: 'CH'
        }],
        from: 134.60625000000002,
        to: 134.61375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 150.07,
          assignment: 'CH(2,6)'
        }],
        from: 150.06625,
        to: 150.07375
      }, {
        signals: [{
          delta: 125.53,
          assignment: 'CH(3,5)'
        }],
        from: 125.52625,
        to: 125.53375
      }, {
        signals: [{
          delta: 138.35,
          assignment: 'CH(4)'
        }],
        from: 138.34625,
        to: 138.35375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 118.28,
          assignment: 'CH(2,5)'
        }],
        from: 118.27625,
        to: 118.28375
      }, {
        signals: [{
          delta: 108.11,
          assignment: 'CH(3,4)'
        }],
        from: 108.10625,
        to: 108.11375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 47.23,
          assignment: 'CH₂(2,5)'
        }],
        from: 47.22625,
        to: 47.23374999999999
      }, {
        signals: [{
          delta: 26.29,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.28625,
        to: 26.29375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          delta: 2.1,
          assignment: 'CH₃'
        }],
        from: 2.09625,
        to: 2.1037500000000002
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 68.83,
          assignment: 'CH₂(2,5)'
        }],
        from: 68.82625,
        to: 68.83375
      }, {
        signals: [{
          delta: 26.48,
          assignment: 'CH₂(3,4)'
        }],
        from: 26.47625,
        to: 26.48375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          delta: 21.5,
          assignment: 'CH₃'
        }],
        from: 21.49625,
        to: 21.50375
      }, {
        signals: [{
          delta: 138.85,
          assignment: 'C(1)'
        }],
        from: 138.84625,
        to: 138.85375
      }, {
        signals: [{
          delta: 129.91,
          assignment: 'CH(2,6)'
        }],
        from: 129.90625,
        to: 129.91375
      }, {
        signals: [{
          delta: 129.2,
          assignment: 'CH(3,5)'
        }],
        from: 129.19625,
        to: 129.20374999999999
      }, {
        signals: [{
          delta: 126.29,
          assignment: 'CH(4)'
        }],
        from: 126.28625000000001,
        to: 126.29375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 11.09,
          assignment: 'CH₃'
        }],
        from: 11.08625,
        to: 11.09375
      }, {
        signals: [{
          delta: 46.96,
          assignment: 'CH₂'
        }],
        from: 46.956250000000004,
        to: 46.96375
      }],
      nucleus: '13C',
      solvent: 'CD₃OD'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          delta: 177.21,
          assignment: 'CO'
        }],
        from: 177.20625,
        to: 177.21375
      }, {
        signals: [{
          delta: 21.03,
          assignment: 'CH₃'
        }],
        from: 21.02625,
        to: 21.03375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          delta: 215.94,
          assignment: 'CO'
        }],
        from: 215.93625,
        to: 215.94375
      }, {
        signals: [{
          delta: 30.89,
          assignment: 'CH₃'
        }],
        from: 30.88625,
        to: 30.89375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          delta: 119.68,
          assignment: 'CN'
        }],
        from: 119.67625000000001,
        to: 119.68375
      }, {
        signals: [{
          delta: 1.47,
          assignment: 'CH₃'
        }],
        from: 1.46625,
        to: 1.47375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          delta: 70.36,
          assignment: '(CH₃)₃C'
        }],
        from: 70.35625,
        to: 70.36375
      }, {
        signals: [{
          delta: 30.29,
          assignment: '(CH₃)₃C'
        }],
        from: 30.28625,
        to: 30.29375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['carbon dioxide'],
      smiles: 'O=C=O',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['carbon disulfide'],
      smiles: 'S=C=S',
      ranges: [{
        signals: [{
          delta: 197.25,
          assignment: 'CS₂'
        }],
        from: 197.24625,
        to: 197.25375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['carbon tetrachloride'],
      smiles: 'ClC(Cl)(Cl)Cl',
      ranges: [{
        signals: [{
          delta: 96.73,
          assignment: 'CCl₄'
        }],
        from: 96.72625000000001,
        to: 96.73375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          delta: 70.14,
          assignment: 'CH₂'
        }],
        from: 70.13625,
        to: 70.14375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 14.77,
          assignment: 'CH₃'
        }],
        from: 14.76625,
        to: 14.77375
      }, {
        signals: [{
          delta: 66.42,
          assignment: 'CH₂'
        }],
        from: 66.41625,
        to: 66.42375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          delta: 58.67,
          assignment: 'CH₃'
        }],
        from: 58.666250000000005,
        to: 58.67375
      }, {
        signals: [{
          delta: 70.05,
          assignment: 'CH₂'
        }],
        from: 70.04625,
        to: 70.05375
      }, {
        signals: [{
          delta: 71.63,
          assignment: 'CH₂'
        }],
        from: 71.62625,
        to: 71.63374999999999
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          delta: 165.53,
          assignment: 'CH'
        }],
        from: 165.52625,
        to: 165.53375
      }, {
        signals: [{
          delta: 37.54,
          assignment: 'CH₃'
        }],
        from: 37.53625,
        to: 37.543749999999996
      }, {
        signals: [{
          delta: 32.03,
          assignment: 'CH₃'
        }],
        from: 32.026250000000005,
        to: 32.03375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          delta: 67.19,
          assignment: 'CH₂'
        }],
        from: 67.18625,
        to: 67.19375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          delta: 58.67,
          assignment: 'CH₃'
        }],
        from: 58.666250000000005,
        to: 58.67375
      }, {
        signals: [{
          delta: 71.49,
          assignment: 'CH₂'
        }],
        from: 71.48625,
        to: 71.49374999999999
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          delta: 17.47,
          assignment: 'CH₃'
        }],
        from: 17.46625,
        to: 17.47375
      }, {
        signals: [{
          delta: 58.05,
          assignment: 'CH₂'
        }],
        from: 58.04625,
        to: 58.053749999999994
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          delta: 21.15,
          assignment: 'CH₃CO'
        }],
        from: 21.14625,
        to: 21.15375
      }, {
        signals: [{
          delta: 175.26,
          assignment: 'CO'
        }],
        from: 175.25625,
        to: 175.26375
      }, {
        signals: [{
          delta: 62.32,
          assignment: 'CH₂'
        }],
        from: 62.316250000000004,
        to: 62.32375
      }, {
        signals: [{
          delta: 13.92,
          assignment: 'CH₃'
        }],
        from: 13.91625,
        to: 13.92375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          delta: 63.17,
          assignment: 'CH₂'
        }],
        from: 63.166250000000005,
        to: 63.17375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['H grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          delta: 2.31,
          assignment: 'CH₃'
        }],
        from: 2.30625,
        to: 2.31375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          delta: 36.46,
          assignment: 'CH₃'
        }],
        from: 36.456250000000004,
        to: 36.46375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          delta: 136.65,
          assignment: 'CH(2)'
        }],
        from: 136.64625,
        to: 136.65375
      }, {
        signals: [{
          delta: 122.43,
          assignment: 'CH(4,5)'
        }],
        from: 122.42625000000001,
        to: 122.43375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          delta: 49.5,
          assignment: 'CH₃'
        }],
        from: 49.49625,
        to: 49.50375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          delta: 63.22,
          assignment: 'CH₃'
        }],
        from: 63.21625,
        to: 63.223749999999995
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          delta: 24.38,
          assignment: 'CH₃'
        }],
        from: 24.37625,
        to: 24.38375
      }, {
        signals: [{
          delta: 64.88,
          assignment: 'CH'
        }],
        from: 64.87625,
        to: 64.88374999999999
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          delta: 149.18,
          assignment: 'CH(2,6)'
        }],
        from: 149.17625,
        to: 149.18375
      }, {
        signals: [{
          delta: 125.12,
          assignment: 'CH(3,5)'
        }],
        from: 125.11625000000001,
        to: 125.12375
      }, {
        signals: [{
          delta: 138.27,
          assignment: 'CH(4)'
        }],
        from: 138.26625,
        to: 138.27375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          delta: 119.06,
          assignment: 'CH(2,5)'
        }],
        from: 119.05625,
        to: 119.06375
      }, {
        signals: [{
          delta: 107.83,
          assignment: 'CH(3,4)'
        }],
        from: 107.82625,
        to: 107.83375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          delta: 46.83,
          assignment: 'CH₂(2,5)'
        }],
        from: 46.82625,
        to: 46.833749999999995
      }, {
        signals: [{
          delta: 25.86,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.85625,
        to: 25.86375
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          delta: 68.68,
          assignment: 'CH₂(2,5)'
        }],
        from: 68.67625000000001,
        to: 68.68375
      }, {
        signals: [{
          delta: 25.67,
          assignment: 'CH₂(3,4)'
        }],
        from: 25.66625,
        to: 25.673750000000002
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [],
      nucleus: '13C',
      solvent: 'D₂O'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          delta: 9.07,
          assignment: 'CH₃'
        }],
        from: 9.06625,
        to: 9.07375
      }, {
        signals: [{
          delta: 47.19,
          assignment: 'CH₂'
        }],
        from: 47.18625,
        to: 47.193749999999994
      }],
      nucleus: '13C',
      solvent: 'D₂O'
    }];

    const protonImpurities = [{
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.46,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 2.45625,
        to: 2.46375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.89,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.88625,
        to: 1.8937499999999998
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.05,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.0462499999999997,
        to: 2.05375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.95,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.94625,
        to: 1.9537499999999999
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.31,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.3062499999999995,
        to: 7.31375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.15,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.14625,
        to: 1.1537499999999998
      }, {
        signals: [{
          js: [],
          delta: 3.16,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 3.15625,
        to: 3.1637500000000003
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.89,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.8862499999999995,
        to: 7.89375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.57,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.5662499999999997,
        to: 3.57375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.44,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.43625,
        to: 1.4437499999999999
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.77,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.76625,
        to: 3.77375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.51,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.50625,
        to: 5.51375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.12,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.0987500000000001,
        to: 1.14125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.38,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.35,
        to: 3.4099999999999997
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.43,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.42625,
        to: 3.4337500000000003
      }, {
        signals: [{
          js: [],
          delta: 3.53,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5262499999999997,
        to: 3.53375
      }, {
        signals: [{
          js: [],
          delta: 3.28,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.2762499999999997,
        to: 3.28375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.91,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.90625,
        to: 7.91375
      }, {
        signals: [{
          js: [],
          delta: 2.88,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.8762499999999998,
        to: 2.88375
      }, {
        signals: [{
          js: [],
          delta: 2.76,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.7562499999999996,
        to: 2.76375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.56,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.55625,
        to: 3.56375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.2762499999999997,
        to: 3.28375
      }, {
        signals: [{
          js: [],
          delta: 3.43,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.42625,
        to: 3.4337500000000003
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.85,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.84625,
        to: 0.85375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.1,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.07875,
        to: 1.12125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.51,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.48,
        to: 3.5399999999999996
      }, {
        signals: [{
          js: [],
          delta: 3.3,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 3.2962499999999997,
        to: 3.30375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.94,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.93625,
        to: 1.9437499999999999
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.04,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.01,
        to: 4.07
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.19,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.16875,
        to: 1.21125
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.36,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.35625,
        to: 5.3637500000000005
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.48,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.47625,
        to: 3.48375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.85,
        to: 0.91,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.29,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.2862500000000001,
        to: 1.29375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.18,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.17625,
        to: 2.1837500000000003
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86875,
        to: 0.91125
      }, {
        signals: [{
          js: [],
          delta: 1.29,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.2862500000000001,
        to: 1.29375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.06625,
        to: 0.07375000000000001
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.58,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.564375,
        to: 2.595625
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.55,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.54625,
        to: 4.55375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.48,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.47625,
        to: 7.483750000000001
      }, {
        signals: [{
          js: [],
          delta: 6.94,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 6.93625,
        to: 6.9437500000000005
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.19,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.18625,
        to: 0.19375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.27,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.26625,
        to: 3.27375
      }, {
        signals: [{
          js: [],
          delta: 3.02,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 3.01625,
        to: 3.02375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.31,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.3062499999999995,
        to: 4.31375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86875,
        to: 0.91125
      }, {
        signals: [{
          js: [],
          delta: 1.31,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.3062500000000001,
        to: 1.31375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.878,
        to: 0.922
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.33,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2715,
        to: 1.3885
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.08,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.06875,
        to: 1.09125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.82,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.7712499999999998,
        to: 3.86875
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.69,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6744999999999999,
        to: 1.7055
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.89,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.873749999999999,
        to: 4.90625
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 4.99,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 4.965,
        to: 5.015000000000001
      }, {
        signals: [{
          js: [],
          delta: 5.79,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.78625,
        to: 5.79375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.54,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.536249999999999,
        to: 8.54375
      }, {
        signals: [{
          js: [],
          delta: 7.25,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.24625,
        to: 7.25375
      }, {
        signals: [{
          js: [],
          delta: 7.65,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.64625,
        to: 7.6537500000000005
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 9.96,
          assignment: 'NH'
        }],
        integration: 1,
        from: 9.95625,
        to: 9.963750000000001
      }, {
        signals: [{
          js: [],
          delta: 6.66,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.65625,
        to: 6.66375
      }, {
        signals: [{
          js: [],
          delta: 6.02,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.016249999999999,
        to: 6.02375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.75,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.74625,
        to: 2.75375
      }, {
        signals: [{
          js: [],
          delta: 1.59,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.5862500000000002,
        to: 1.59375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.11,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.10625,
        to: 0.11375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.62,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.61625,
        to: 3.6237500000000002
      }, {
        signals: [{
          js: [],
          delta: 1.79,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.7862500000000001,
        to: 1.79375
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.31,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.30625,
        to: 2.31375
      }, {
        signals: [{
          js: [],
          delta: 7.1,
          assignment: 'CH(2,4,6)'
        }],
        integration: 3,
        from: 7.0962499999999995,
        to: 7.10375
      }, {
        signals: [{
          js: [],
          delta: 7.19,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.18625,
        to: 7.1937500000000005
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.97,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.94875,
        to: 0.99125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.46,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.43,
        to: 2.4899999999999998
      }],
      nucleus: '1H',
      solvent: 'THF-d₈'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.52,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 1.51625,
        to: 1.52375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.06,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.05625,
        to: 2.06375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.12,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.11625,
        to: 2.1237500000000002
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.97,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.96625,
        to: 1.97375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.35,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.3462499999999995,
        to: 7.35375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.24,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.23625,
        to: 1.24375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.32,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.31625,
        to: 7.32375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.59,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.5862499999999997,
        to: 3.59375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.44,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.43625,
        to: 1.4437499999999999
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.76,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.7562499999999996,
        to: 3.76375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.33,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.32625,
        to: 5.33375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.15,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.12875,
        to: 1.17125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.43,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.4000000000000004,
        to: 3.46
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.57,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5662499999999997,
        to: 3.57375
      }, {
        signals: [{
          js: [],
          delta: 3.5,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.49625,
        to: 3.50375
      }, {
        signals: [{
          js: [],
          delta: 3.33,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.32625,
        to: 3.33375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.96,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.95625,
        to: 7.96375
      }, {
        signals: [{
          js: [],
          delta: 2.91,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.90625,
        to: 2.9137500000000003
      }, {
        signals: [{
          js: [],
          delta: 2.82,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.8162499999999997,
        to: 2.82375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.65,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.6462499999999998,
        to: 3.65375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.34,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.3362499999999997,
        to: 3.34375
      }, {
        signals: [{
          js: [],
          delta: 3.49,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.48625,
        to: 3.4937500000000004
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.85,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.84625,
        to: 0.85375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.19,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.16875,
        to: 1.21125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.66,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.6300000000000003,
        to: 3.69
      }, {
        signals: [{
          js: [],
          delta: 1.33,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 1.3262500000000002,
        to: 1.33375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 2,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.99625,
        to: 2.00375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.08,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.05,
        to: 4.11
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.23,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.20875,
        to: 1.25125
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.4,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.39625,
        to: 5.4037500000000005
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.66,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.65625,
        to: 3.6637500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.84,
        to: 0.9,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.27,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.26625,
        to: 1.27375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.2,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.19625,
        to: 2.2037500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86875,
        to: 0.91125
      }, {
        signals: [{
          js: [],
          delta: 1.27,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.26625,
        to: 1.27375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.06625,
        to: 0.07375000000000001
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.6,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.584375,
        to: 2.615625
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.59,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.58625,
        to: 4.59375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.63,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.62625,
        to: 7.63375
      }, {
        signals: [{
          js: [],
          delta: 7.07,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.06625,
        to: 7.07375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.21,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.20625,
        to: 0.21375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.42,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.41625,
        to: 3.42375
      }, {
        signals: [{
          js: [],
          delta: 1.09,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 1.0862500000000002,
        to: 1.09375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.31,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.3062499999999995,
        to: 4.31375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86875,
        to: 0.91125
      }, {
        signals: [{
          js: [],
          delta: 1.3,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.2962500000000001,
        to: 1.30375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.878,
        to: 0.922
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.32,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2615,
        to: 1.3785
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.17,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.15875,
        to: 1.18125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.97,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.92125,
        to: 4.01875
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.71,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6945,
        to: 1.7255
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.93,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.913749999999999,
        to: 4.94625
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.03,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 5.005,
        to: 5.055000000000001
      }, {
        signals: [{
          js: [],
          delta: 5.84,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.83625,
        to: 5.84375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.59,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.58625,
        to: 8.59375
      }, {
        signals: [{
          js: [],
          delta: 7.28,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.27625,
        to: 7.28375
      }, {
        signals: [{
          js: [],
          delta: 7.68,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.67625,
        to: 7.68375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.69,
          assignment: 'NH'
        }],
        integration: 1,
        from: 8.68625,
        to: 8.69375
      }, {
        signals: [{
          js: [],
          delta: 6.79,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.78625,
        to: 6.79375
      }, {
        signals: [{
          js: [],
          delta: 6.19,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.18625,
        to: 6.1937500000000005
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.82,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.8162499999999997,
        to: 2.82375
      }, {
        signals: [{
          js: [],
          delta: 1.67,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.66625,
        to: 1.6737499999999998
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.09,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.08625,
        to: 0.09375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.69,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.68625,
        to: 3.69375
      }, {
        signals: [{
          js: [],
          delta: 1.82,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.8162500000000001,
        to: 1.82375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.34,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.3362499999999997,
        to: 2.34375
      }, {
        signals: [{
          js: [],
          delta: 7.15,
          assignment: 'CH(2,4,6)'
        }],
        integration: 3,
        from: 7.14625,
        to: 7.1537500000000005
      }, {
        signals: [{
          js: [],
          delta: 7.24,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.23625,
        to: 7.24375
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.99,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.96875,
        to: 1.01125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.48,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.45,
        to: 2.51
      }],
      nucleus: '1H',
      solvent: 'CD₂Cl₂'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.56,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 1.5562500000000001,
        to: 1.56375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.1,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.09625,
        to: 2.1037500000000002
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.17,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.16625,
        to: 2.17375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.1,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.09625,
        to: 2.1037500000000002
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.36,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.35625,
        to: 7.3637500000000005
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.27625,
        to: 1.28375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.26,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.25625,
        to: 7.26375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.67,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.66625,
        to: 3.67375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.43,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.42625,
        to: 1.4337499999999999
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.73,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.72625,
        to: 3.73375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.3,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.29625,
        to: 5.30375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.21,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.18875,
        to: 1.23125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.48,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.45,
        to: 3.51
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.65,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.6462499999999998,
        to: 3.65375
      }, {
        signals: [{
          js: [],
          delta: 3.57,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5662499999999997,
        to: 3.57375
      }, {
        signals: [{
          js: [],
          delta: 3.39,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.38625,
        to: 3.3937500000000003
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.02,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 8.01625,
        to: 8.02375
      }, {
        signals: [{
          js: [],
          delta: 2.96,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.95625,
        to: 2.96375
      }, {
        signals: [{
          js: [],
          delta: 2.88,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.8762499999999998,
        to: 2.88375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.71,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.70625,
        to: 3.71375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.4,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.3962499999999998,
        to: 3.40375
      }, {
        signals: [{
          js: [],
          delta: 3.55,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5462499999999997,
        to: 3.55375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.87,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86625,
        to: 0.87375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.25,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.22875,
        to: 1.27125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.72,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.6900000000000004,
        to: 3.75
      }, {
        signals: [{
          js: [],
          delta: 1.32,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 1.3162500000000001,
        to: 1.32375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.05,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 2.0462499999999997,
        to: 2.05375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.12,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.09,
        to: 4.15
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.26,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.23875,
        to: 1.28125
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.4,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.39625,
        to: 5.4037500000000005
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.76,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.7562499999999996,
        to: 3.76375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.84,
        to: 0.87,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.25,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.24625,
        to: 1.25375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.24,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.23625,
        to: 2.2437500000000004
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.88,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.85875,
        to: 0.90125
      }, {
        signals: [{
          js: [],
          delta: 1.26,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.25625,
        to: 1.26375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.06625,
        to: 0.07375000000000001
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.65,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.634375,
        to: 2.665625
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.62,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.61625,
        to: 4.62375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.67,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.66625,
        to: 7.67375
      }, {
        signals: [{
          js: [],
          delta: 7.1,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.0962499999999995,
        to: 7.10375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.22,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.21625,
        to: 0.22375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.49,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.48625,
        to: 3.4937500000000004
      }, {
        signals: [{
          js: [],
          delta: 1.09,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 1.0862500000000002,
        to: 1.09375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.33,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.32625,
        to: 4.33375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.88,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.85875,
        to: 0.90125
      }, {
        signals: [{
          js: [],
          delta: 1.27,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.26625,
        to: 1.27375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.878,
        to: 0.922
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.32,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2615,
        to: 1.3785
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.22,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.20875,
        to: 1.23125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 4.04,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.99125,
        to: 4.08875
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.73,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.7145,
        to: 1.7455
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.94,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.92375,
        to: 4.956250000000001
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.03,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 5.005,
        to: 5.055000000000001
      }, {
        signals: [{
          js: [],
          delta: 5.83,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.82625,
        to: 5.83375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.62,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.616249999999999,
        to: 8.62375
      }, {
        signals: [{
          js: [],
          delta: 7.29,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.28625,
        to: 7.29375
      }, {
        signals: [{
          js: [],
          delta: 7.68,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.67625,
        to: 7.68375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.4,
          assignment: 'NH'
        }],
        integration: 1,
        from: 8.39625,
        to: 8.40375
      }, {
        signals: [{
          js: [],
          delta: 6.83,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.82625,
        to: 6.83375
      }, {
        signals: [{
          js: [],
          delta: 6.26,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.25625,
        to: 6.26375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.87,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.86625,
        to: 2.8737500000000002
      }, {
        signals: [{
          js: [],
          delta: 1.68,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.67625,
        to: 1.6837499999999999
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.06625,
        to: 0.07375000000000001
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.76,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.7562499999999996,
        to: 3.76375
      }, {
        signals: [{
          js: [],
          delta: 1.85,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.8462500000000002,
        to: 1.85375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.36,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.3562499999999997,
        to: 2.36375
      }, {
        signals: [{
          js: [],
          delta: 7.17,
          assignment: 'CH(2,4,6)'
        }],
        integration: 3,
        from: 7.16625,
        to: 7.17375
      }, {
        signals: [{
          js: [],
          delta: 7.25,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.24625,
        to: 7.25375
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.03,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.00875,
        to: 1.05125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.53,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.5,
        to: 2.5599999999999996
      }],
      nucleus: '1H',
      solvent: 'CDCl₃'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.43,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 0.42625,
        to: 0.43374999999999997
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.57,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.5662500000000001,
        to: 1.57375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.57,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.5662500000000001,
        to: 1.57375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.69,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 0.6862499999999999,
        to: 0.69375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.12,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.11625,
        to: 7.12375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.03,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.02625,
        to: 1.03375
      }, {
        signals: [{
          js: [],
          delta: 0.58,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 0.5762499999999999,
        to: 0.58375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 6.1,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 6.0962499999999995,
        to: 6.10375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.36,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.3562499999999997,
        to: 3.36375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.4,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.39625,
        to: 1.4037499999999998
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.91,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.90625,
        to: 2.9137500000000003
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.32,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 4.31625,
        to: 4.32375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.1,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.07875,
        to: 1.12125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.25,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.22,
        to: 3.28
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.43,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.42625,
        to: 3.4337500000000003
      }, {
        signals: [{
          js: [],
          delta: 3.31,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.30625,
        to: 3.31375
      }, {
        signals: [{
          js: [],
          delta: 3.12,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.11625,
        to: 3.1237500000000002
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.57,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.56625,
        to: 7.57375
      }, {
        signals: [{
          js: [],
          delta: 2.37,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.36625,
        to: 2.3737500000000002
      }, {
        signals: [{
          js: [],
          delta: 1.96,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.95625,
        to: 1.9637499999999999
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.33,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.32625,
        to: 3.33375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.12,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.11625,
        to: 3.1237500000000002
      }, {
        signals: [{
          js: [],
          delta: 3.31,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.30625,
        to: 3.31375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.81,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.80625,
        to: 0.8137500000000001
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.97,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 0.94875,
        to: 0.99125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.36,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.33,
        to: 3.3899999999999997
      }, {
        signals: [{
          js: [],
          delta: 0.83,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 0.8262499999999999,
        to: 0.83375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.69,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.68625,
        to: 1.6937499999999999
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.87,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 3.8400000000000003,
        to: 3.9
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.94,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 0.91875,
        to: 0.9612499999999999
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.25,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.24625,
        to: 5.25375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.36,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.3562499999999997,
        to: 3.36375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.89,
        to: 0.96,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.33,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.3262500000000002,
        to: 1.33375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.1,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.09625,
        to: 2.1037500000000002
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.88,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.85875,
        to: 0.90125
      }, {
        signals: [{
          js: [],
          delta: 1.22,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.21625,
        to: 1.22375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.1,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.09625,
        to: 0.10375000000000001
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.42,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.404375,
        to: 2.435625
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.5,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.49625,
        to: 4.50375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.3,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.29625,
        to: 7.30375
      }, {
        signals: [{
          js: [],
          delta: 6.86,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 6.85625,
        to: 6.8637500000000005
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.17,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.16625,
        to: 0.17375000000000002
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.03,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.0262499999999997,
        to: 3.03375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.01,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.0062499999999996,
        to: 3.01375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.87,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.84875,
        to: 0.89125
      }, {
        signals: [{
          js: [],
          delta: 1.25,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.24625,
        to: 1.25375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.868,
        to: 0.912
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.32,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2615,
        to: 1.3785
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 0.95,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.93875,
        to: 0.9612499999999999
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.65,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.60125,
        to: 3.69875
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.55,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.5345,
        to: 1.5655000000000001
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.92,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.90375,
        to: 4.93625
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 4.98,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 4.955,
        to: 5.005000000000001
      }, {
        signals: [{
          js: [],
          delta: 5.7,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.69625,
        to: 5.70375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.47,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.46625,
        to: 8.47375
      }, {
        signals: [{
          js: [],
          delta: 6.67,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 6.66625,
        to: 6.67375
      }, {
        signals: [{
          js: [],
          delta: 6.99,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 6.98625,
        to: 6.99375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.71,
          assignment: 'NH'
        }],
        integration: 1,
        from: 7.70625,
        to: 7.71375
      }, {
        signals: [{
          js: [],
          delta: 6.43,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.42625,
        to: 6.43375
      }, {
        signals: [{
          js: [],
          delta: 6.27,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.266249999999999,
        to: 6.27375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.54,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.53625,
        to: 2.54375
      }, {
        signals: [{
          js: [],
          delta: 1.36,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.3562500000000002,
        to: 1.36375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.26,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.25625000000000003,
        to: 0.26375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.54,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.53625,
        to: 3.54375
      }, {
        signals: [{
          js: [],
          delta: 1.43,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.42625,
        to: 1.4337499999999999
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.11,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.1062499999999997,
        to: 2.11375
      }, {
        signals: [],
        integration: 3,
        from: 6.96,
        to: 7.01,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 7.09,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.08625,
        to: 7.09375
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.95,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.92875,
        to: 0.97125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.39,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.3600000000000003,
        to: 2.42
      }],
      nucleus: '1H',
      solvent: 'toluene-d₈'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.4,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 0.39625000000000005,
        to: 0.40375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.52,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.51625,
        to: 1.52375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.55,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.5462500000000001,
        to: 1.55375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.58,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 0.5762499999999999,
        to: 0.58375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.15,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.14625,
        to: 7.1537500000000005
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.05,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.0462500000000001,
        to: 1.05375
      }, {
        signals: [{
          js: [],
          delta: 0.63,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 0.62625,
        to: 0.63375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 6.15,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 6.14625,
        to: 6.1537500000000005
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.39,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.38625,
        to: 3.3937500000000003
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.4,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.39625,
        to: 1.4037499999999998
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.9,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.8962499999999998,
        to: 2.90375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.27,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 4.266249999999999,
        to: 4.27375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.11,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.08875,
        to: 1.13125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.26,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.23,
        to: 3.2899999999999996
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.46,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.45625,
        to: 3.46375
      }, {
        signals: [{
          js: [],
          delta: 3.34,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.3362499999999997,
        to: 3.34375
      }, {
        signals: [{
          js: [],
          delta: 3.11,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.1062499999999997,
        to: 3.11375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.63,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.62625,
        to: 7.63375
      }, {
        signals: [{
          js: [],
          delta: 2.36,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.3562499999999997,
        to: 2.36375
      }, {
        signals: [{
          js: [],
          delta: 1.86,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.8562500000000002,
        to: 1.86375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.35,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.34625,
        to: 3.3537500000000002
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.12,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.11625,
        to: 3.1237500000000002
      }, {
        signals: [{
          js: [],
          delta: 3.33,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.32625,
        to: 3.33375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.8,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.79625,
        to: 0.8037500000000001
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.96,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 0.93875,
        to: 0.98125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.34,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.31,
        to: 3.3699999999999997
      }, {
        signals: [{
          js: [],
          delta: 0.5,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 0.49625,
        to: 0.50375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.65,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.64625,
        to: 1.6537499999999998
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.89,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 3.8600000000000003,
        to: 3.92
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.92,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 0.89875,
        to: 0.94125
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.25,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.24625,
        to: 5.25375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.41,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.40625,
        to: 3.4137500000000003
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.9,
        to: 0.98,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.32,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.3162500000000001,
        to: 1.32375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.13,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.1262499999999998,
        to: 2.13375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86875,
        to: 0.91125
      }, {
        signals: [{
          js: [],
          delta: 1.24,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.23625,
        to: 1.24375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.12,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.11624999999999999,
        to: 0.12375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.4,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.384375,
        to: 2.415625
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.47,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.46625,
        to: 4.47375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.33,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.32625,
        to: 7.33375
      }, {
        signals: [{
          js: [],
          delta: 6.9,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 6.89625,
        to: 6.9037500000000005
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.16,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.15625,
        to: 0.16375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.0662499999999997,
        to: 3.07375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.94,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.93625,
        to: 2.94375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.87,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.84875,
        to: 0.89125
      }, {
        signals: [{
          js: [],
          delta: 1.23,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.22625,
        to: 1.23375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.86,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.838,
        to: 0.882
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.26,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2015,
        to: 1.3185
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 0.95,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.93875,
        to: 0.9612499999999999
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.67,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.62125,
        to: 3.71875
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.55,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.5345,
        to: 1.5655000000000001
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.95,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.93375,
        to: 4.9662500000000005
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.01,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 4.984999999999999,
        to: 5.035
      }, {
        signals: [{
          js: [],
          delta: 5.72,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.71625,
        to: 5.72375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.53,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.52625,
        to: 8.53375
      }, {
        signals: [{
          js: [],
          delta: 6.66,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 6.65625,
        to: 6.66375
      }, {
        signals: [{
          js: [],
          delta: 6.98,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 6.97625,
        to: 6.983750000000001
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.8,
          assignment: 'NH'
        }],
        integration: 1,
        from: 7.79625,
        to: 7.80375
      }, {
        signals: [{
          js: [],
          delta: 6.48,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.47625,
        to: 6.483750000000001
      }, {
        signals: [{
          js: [],
          delta: 6.37,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.36625,
        to: 6.37375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.54,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.53625,
        to: 2.54375
      }, {
        signals: [{
          js: [],
          delta: 1.33,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.3262500000000002,
        to: 1.33375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.29,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.28625,
        to: 0.29374999999999996
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.57,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.5662499999999997,
        to: 3.57375
      }, {
        signals: [{
          js: [],
          delta: 1.4,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.39625,
        to: 1.4037499999999998
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.11,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.1062499999999997,
        to: 2.11375
      }, {
        signals: [{
          js: [],
          delta: 7.02,
          assignment: 'CH(2,4,6)'
        }],
        integration: 3,
        from: 7.016249999999999,
        to: 7.02375
      }, {
        signals: [{
          js: [],
          delta: 7.13,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.12625,
        to: 7.13375
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.96,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.93875,
        to: 0.98125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.4,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.37,
        to: 2.4299999999999997
      }],
      nucleus: '1H',
      solvent: 'C₆D₆'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.03,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 1.02625,
        to: 1.03375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.76,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.75625,
        to: 1.76375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.77,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.76625,
        to: 1.77375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.21,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.20625,
        to: 1.2137499999999999
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.2,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.19625,
        to: 7.20375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.12,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.1162500000000002,
        to: 1.12375
      }, {
        signals: [{
          js: [],
          delta: 1.3,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 1.2962500000000001,
        to: 1.30375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 6.74,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 6.73625,
        to: 6.74375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.41,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.40625,
        to: 3.4137500000000003
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.37,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.3662500000000002,
        to: 1.37375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.26,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.2562499999999996,
        to: 3.26375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.77,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 4.766249999999999,
        to: 4.77375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.1,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.07875,
        to: 1.12125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.31,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.2800000000000002,
        to: 3.34
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.49,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.48625,
        to: 3.4937500000000004
      }, {
        signals: [{
          js: [],
          delta: 3.37,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.36625,
        to: 3.3737500000000002
      }, {
        signals: [{
          js: [],
          delta: 3.16,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.15625,
        to: 3.1637500000000003
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.73,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.72625,
        to: 7.733750000000001
      }, {
        signals: [{
          js: [],
          delta: 2.51,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.5062499999999996,
        to: 2.51375
      }, {
        signals: [{
          js: [],
          delta: 2.3,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.2962499999999997,
        to: 2.30375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.45,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.44625,
        to: 3.4537500000000003
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.17,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.16625,
        to: 3.17375
      }, {
        signals: [{
          js: [],
          delta: 3.37,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.36625,
        to: 3.3737500000000002
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.79,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.78625,
        to: 0.7937500000000001
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.06,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.03875,
        to: 1.08125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.51,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.48,
        to: 3.5399999999999996
      }, {
        signals: [{
          js: [],
          delta: 1.39,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 1.38625,
        to: 1.3937499999999998
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.78,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.77625,
        to: 1.78375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.96,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 3.93,
        to: 3.9899999999999998
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.04,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.01875,
        to: 1.06125
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.29,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.28625,
        to: 5.29375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.58,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.57625,
        to: 3.58375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.86,
        to: 0.92,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.3,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.2962500000000001,
        to: 1.30375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.1,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.09625,
        to: 2.1037500000000002
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.85,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.82875,
        to: 0.87125
      }, {
        signals: [{
          js: [],
          delta: 1.19,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.18625,
        to: 1.1937499999999999
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.1,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.09625,
        to: 0.10375000000000001
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.47,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.454375,
        to: 2.485625
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.49,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.48625,
        to: 4.49375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.53,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.52625,
        to: 7.53375
      }, {
        signals: [{
          js: [],
          delta: 7.01,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.00625,
        to: 7.01375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.15,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.14625,
        to: 0.15375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.25,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.24625,
        to: 3.25375
      }, {
        signals: [{
          js: [],
          delta: 1.3,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 1.2962500000000001,
        to: 1.30375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.59,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.5862499999999997,
        to: 3.59375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.84,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.81875,
        to: 0.86125
      }, {
        signals: [{
          js: [],
          delta: 1.23,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.22625,
        to: 1.23375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.84,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.818,
        to: 0.862
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.26,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2015,
        to: 1.3185
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.04,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.02875,
        to: 1.05125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.82,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.7712499999999998,
        to: 3.86875
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.58,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.5645,
        to: 1.5955000000000001
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.91,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.89375,
        to: 4.9262500000000005
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 4.98,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 4.955,
        to: 5.005000000000001
      }, {
        signals: [{
          js: [],
          delta: 5.72,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.71625,
        to: 5.72375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.51,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.50625,
        to: 8.51375
      }, {
        signals: [{
          js: [],
          delta: 6.9,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 6.89625,
        to: 6.9037500000000005
      }, {
        signals: [{
          js: [],
          delta: 7.25,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.24625,
        to: 7.25375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.61,
          assignment: 'NH'
        }],
        integration: 1,
        from: 8.60625,
        to: 8.61375
      }, {
        signals: [{
          js: [],
          delta: 6.62,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.61625,
        to: 6.62375
      }, {
        signals: [{
          js: [],
          delta: 6.27,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.266249999999999,
        to: 6.27375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.64,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.63625,
        to: 2.6437500000000003
      }, {
        signals: [{
          js: [],
          delta: 1.43,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.42625,
        to: 1.4337499999999999
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.14,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.13625,
        to: 0.14375000000000002
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.59,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.5862499999999997,
        to: 3.59375
      }, {
        signals: [{
          js: [],
          delta: 1.55,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.5462500000000001,
        to: 1.55375
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.16,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.15625,
        to: 2.1637500000000003
      }, {
        signals: [],
        integration: 3,
        from: 7.01,
        to: 7.08,
        multiplicity: 'm'
      }, {
        signals: [],
        integration: 2,
        from: 7.1,
        to: 7.17,
        multiplicity: 'm'
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.93,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.9087500000000001,
        to: 0.95125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.39,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.3600000000000003,
        to: 2.42
      }],
      nucleus: '1H',
      solvent: 'C₆D₅Cl'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.84,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 2.8362499999999997,
        to: 2.84375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.96,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.95625,
        to: 1.9637499999999999
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.09,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.0862499999999997,
        to: 2.09375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.05,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.0462499999999997,
        to: 2.05375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.36,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.35625,
        to: 7.3637500000000005
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.18,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.17625,
        to: 1.1837499999999999
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.02,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 8.01625,
        to: 8.02375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.59,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.5862499999999997,
        to: 3.59375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.43,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.42625,
        to: 1.4337499999999999
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.87,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.86625,
        to: 3.8737500000000002
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.63,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.62625,
        to: 5.63375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.11,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.08875,
        to: 1.13125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.41,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.3800000000000003,
        to: 3.44
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.56,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.55625,
        to: 3.56375
      }, {
        signals: [{
          js: [],
          delta: 3.47,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.46625,
        to: 3.4737500000000003
      }, {
        signals: [{
          js: [],
          delta: 3.28,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.2762499999999997,
        to: 3.28375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.96,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.95625,
        to: 7.96375
      }, {
        signals: [{
          js: [],
          delta: 2.94,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.93625,
        to: 2.94375
      }, {
        signals: [{
          js: [],
          delta: 2.78,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.7762499999999997,
        to: 2.78375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.59,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.5862499999999997,
        to: 3.59375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.2762499999999997,
        to: 3.28375
      }, {
        signals: [{
          js: [],
          delta: 3.46,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.45625,
        to: 3.46375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.83,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.8262499999999999,
        to: 0.83375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.12,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.0987500000000001,
        to: 1.14125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.57,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.54,
        to: 3.5999999999999996
      }, {
        signals: [{
          js: [],
          delta: 3.39,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 3.38625,
        to: 3.3937500000000003
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.97,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.96625,
        to: 1.97375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.05,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.02,
        to: 4.08
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.2,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.17875,
        to: 1.22125
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.38,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.37625,
        to: 5.38375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.28,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.2762499999999997,
        to: 3.28375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.89625,
        to: 0.90375
      }, {
        signals: [{
          js: [],
          delta: 1.29,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.2862500000000001,
        to: 1.29375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.17,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.16625,
        to: 2.17375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.88,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.85875,
        to: 0.90125
      }, {
        signals: [{
          js: [],
          delta: 1.28,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.27625,
        to: 1.28375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.06625,
        to: 0.07375000000000001
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.59,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.574375,
        to: 2.605625
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.54,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.53625,
        to: 4.54375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.62,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.61625,
        to: 7.62375
      }, {
        signals: [{
          js: [],
          delta: 7.04,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.03625,
        to: 7.04375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.17,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.16625,
        to: 0.17375000000000002
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.31,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.30625,
        to: 3.31375
      }, {
        signals: [{
          js: [],
          delta: 3.12,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 3.11625,
        to: 3.1237500000000002
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.43,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.42625,
        to: 4.43375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.88,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.85875,
        to: 0.90125
      }, {
        signals: [{
          js: [],
          delta: 1.27,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.26625,
        to: 1.27375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.88,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.858,
        to: 0.902
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.31,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2515,
        to: 1.3685
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.1,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.08875,
        to: 1.11125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.9,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.85125,
        to: 3.94875
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.68,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6644999999999999,
        to: 1.6955
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.9,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.88375,
        to: 4.916250000000001
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 4.975,
        to: 5.025
      }, {
        signals: [{
          js: [],
          delta: 5.81,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.8062499999999995,
        to: 5.81375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.58,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.57625,
        to: 8.58375
      }, {
        signals: [{
          js: [],
          delta: 7.35,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.3462499999999995,
        to: 7.35375
      }, {
        signals: [{
          js: [],
          delta: 7.76,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.75625,
        to: 7.76375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 10.02,
          assignment: 'NH'
        }],
        integration: 1,
        from: 10.01625,
        to: 10.02375
      }, {
        signals: [{
          js: [],
          delta: 6.77,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.766249999999999,
        to: 6.77375
      }, {
        signals: [{
          js: [],
          delta: 6.07,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.06625,
        to: 6.07375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.13,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.12625,
        to: 0.13375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.63,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.6262499999999998,
        to: 3.63375
      }, {
        signals: [{
          js: [],
          delta: 1.79,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.7862500000000001,
        to: 1.79375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.32,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.3162499999999997,
        to: 2.32375
      }, {
        signals: [],
        integration: 3,
        from: 7.1,
        to: 7.2,
        multiplicity: 'm'
      }, {
        signals: [],
        integration: 2,
        from: 7.1,
        to: 7.2,
        multiplicity: 'm'
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.96,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.93875,
        to: 0.98125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.45,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.4200000000000004,
        to: 2.48
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂CO'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.33,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 3.32625,
        to: 3.33375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.91,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.90625,
        to: 1.9137499999999998
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.09,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.0862499999999997,
        to: 2.09375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.0662499999999997,
        to: 2.07375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.37,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.36625,
        to: 7.37375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.11,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.1062500000000002,
        to: 1.11375
      }, {
        signals: [{
          js: [],
          delta: 4.19,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 4.18625,
        to: 4.1937500000000005
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.32,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 8.31625,
        to: 8.32375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.51,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.5062499999999996,
        to: 3.51375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.4,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.39625,
        to: 1.4037499999999998
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.9,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.8962499999999998,
        to: 3.90375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.76,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.75625,
        to: 5.76375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.09,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.06875,
        to: 1.11125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.38,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.35,
        to: 3.4099999999999997
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.51,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5062499999999996,
        to: 3.51375
      }, {
        signals: [{
          js: [],
          delta: 3.38,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.3762499999999998,
        to: 3.38375
      }, {
        signals: [{
          js: [],
          delta: 3.24,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.23625,
        to: 3.2437500000000004
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.95,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.94625,
        to: 7.95375
      }, {
        signals: [{
          js: [],
          delta: 2.89,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.88625,
        to: 2.8937500000000003
      }, {
        signals: [{
          js: [],
          delta: 2.73,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.72625,
        to: 2.73375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.57,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.5662499999999997,
        to: 3.57375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.24,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.23625,
        to: 3.2437500000000004
      }, {
        signals: [{
          js: [],
          delta: 3.43,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.42625,
        to: 3.4337500000000003
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.82,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.8162499999999999,
        to: 0.82375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.06,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.03875,
        to: 1.08125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.44,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.41,
        to: 3.4699999999999998
      }, {
        signals: [{
          js: [],
          delta: 4.63,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 4.62625,
        to: 4.63375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.99,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.98625,
        to: 1.99375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.03,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4,
        to: 4.0600000000000005
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.17,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.14875,
        to: 1.19125
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.41,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.40625,
        to: 5.41375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.34,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.3362499999999997,
        to: 3.34375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.82,
        to: 0.88,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.24,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.23625,
        to: 1.24375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.14,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.13625,
        to: 2.1437500000000003
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.86,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.83875,
        to: 0.88125
      }, {
        signals: [{
          js: [],
          delta: 1.25,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.24625,
        to: 1.25375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.06,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.056249999999999994,
        to: 0.06375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.53,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.514375,
        to: 2.545625
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.61,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.60625,
        to: 4.6137500000000005
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.63,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.62625,
        to: 7.63375
      }, {
        signals: [{
          js: [],
          delta: 7.01,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.00625,
        to: 7.01375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.2,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.19625,
        to: 0.20375000000000001
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.16,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.15625,
        to: 3.1637500000000003
      }, {
        signals: [{
          js: [],
          delta: 4.01,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 4.00625,
        to: 4.01375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.42,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.41625,
        to: 4.42375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.86,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.83875,
        to: 0.88125
      }, {
        signals: [{
          js: [],
          delta: 1.27,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.26625,
        to: 1.27375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.87,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.848,
        to: 0.892
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.29,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2315,
        to: 1.3485
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.04,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.02875,
        to: 1.05125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.78,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.7312499999999997,
        to: 3.82875
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.68,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6644999999999999,
        to: 1.6955
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.94,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.92375,
        to: 4.956250000000001
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.03,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 5.005,
        to: 5.055000000000001
      }, {
        signals: [{
          js: [],
          delta: 5.8,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.79625,
        to: 5.80375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.58,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.57625,
        to: 8.58375
      }, {
        signals: [{
          js: [],
          delta: 7.39,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.3862499999999995,
        to: 7.39375
      }, {
        signals: [{
          js: [],
          delta: 7.79,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.78625,
        to: 7.79375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 10.75,
          assignment: 'NH'
        }],
        integration: 1,
        from: 10.74625,
        to: 10.75375
      }, {
        signals: [{
          js: [],
          delta: 6.73,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.72625,
        to: 6.733750000000001
      }, {
        signals: [{
          js: [],
          delta: 6.01,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.00625,
        to: 6.01375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.67,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.66625,
        to: 2.67375
      }, {
        signals: [{
          js: [],
          delta: 1.55,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.5462500000000001,
        to: 1.55375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: -0.06,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: -0.06375,
        to: -0.056249999999999994
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.6,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.59625,
        to: 3.6037500000000002
      }, {
        signals: [{
          js: [],
          delta: 1.76,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.75625,
        to: 1.76375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.3,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.2962499999999997,
        to: 2.30375
      }, {
        signals: [{
          js: [],
          delta: 7.18,
          assignment: 'CH(2,4,6)'
        }],
        integration: 3,
        from: 7.17625,
        to: 7.18375
      }, {
        signals: [{
          js: [],
          delta: 7.25,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.24625,
        to: 7.25375
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.93,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.9087500000000001,
        to: 0.95125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.43,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.4000000000000004,
        to: 2.46
      }],
      nucleus: '1H',
      solvent: '(CD₃)₂SO'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.13,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 2.1262499999999998,
        to: 2.13375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.96,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.95625,
        to: 1.9637499999999999
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.08,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.07625,
        to: 2.08375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.96,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.95625,
        to: 1.9637499999999999
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.37,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.36625,
        to: 7.37375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.16,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.15625,
        to: 1.1637499999999998
      }, {
        signals: [{
          js: [],
          delta: 2.18,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 2.17625,
        to: 2.1837500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.58,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.57625,
        to: 7.58375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.51,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.5062499999999996,
        to: 3.51375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.44,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.43625,
        to: 1.4437499999999999
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.81,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.80625,
        to: 3.81375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.44,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.43625,
        to: 5.4437500000000005
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.12,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.0987500000000001,
        to: 1.14125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.42,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.39,
        to: 3.4499999999999997
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.53,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5262499999999997,
        to: 3.53375
      }, {
        signals: [{
          js: [],
          delta: 3.45,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.44625,
        to: 3.4537500000000003
      }, {
        signals: [{
          js: [],
          delta: 3.29,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.28625,
        to: 3.29375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.92,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.91625,
        to: 7.92375
      }, {
        signals: [{
          js: [],
          delta: 2.89,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.88625,
        to: 2.8937500000000003
      }, {
        signals: [{
          js: [],
          delta: 2.77,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.76625,
        to: 2.77375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.6,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.59625,
        to: 3.6037500000000002
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.2762499999999997,
        to: 3.28375
      }, {
        signals: [{
          js: [],
          delta: 3.45,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.44625,
        to: 3.4537500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.85,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.84625,
        to: 0.85375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.12,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.0987500000000001,
        to: 1.14125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.54,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.5100000000000002,
        to: 3.57
      }, {
        signals: [{
          js: [],
          delta: 2.47,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 2.46625,
        to: 2.4737500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.97,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 1.96625,
        to: 1.97375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.06,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.029999999999999,
        to: 4.09
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.2,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.17875,
        to: 1.22125
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.41,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.40625,
        to: 5.41375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.51,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5062499999999996,
        to: 3.51375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.19,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.18625,
        to: 2.19375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86875,
        to: 0.91125
      }, {
        signals: [{
          js: [],
          delta: 1.28,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.27625,
        to: 1.28375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.06625,
        to: 0.07375000000000001
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.57,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.554375,
        to: 2.585625
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.57,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.56625,
        to: 4.57375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.57,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.56625,
        to: 7.57375
      }, {
        signals: [{
          js: [],
          delta: 7.01,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.00625,
        to: 7.01375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.2,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.19625,
        to: 0.20375000000000001
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.2762499999999997,
        to: 3.28375
      }, {
        signals: [{
          js: [],
          delta: 2.16,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 2.15625,
        to: 2.1637500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.31,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.3062499999999995,
        to: 4.31375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.89,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.86875,
        to: 0.91125
      }, {
        signals: [{
          js: [],
          delta: 1.29,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.2862500000000001,
        to: 1.29375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.878,
        to: 0.922
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.33,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2715,
        to: 1.3885
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.09,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.07875,
        to: 1.10125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.87,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.82125,
        to: 3.91875
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.7,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6844999999999999,
        to: 1.7155
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.93,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.913749999999999,
        to: 4.94625
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.04,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 5.015,
        to: 5.065
      }, {
        signals: [{
          js: [],
          delta: 5.85,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.8462499999999995,
        to: 5.85375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.57,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.56625,
        to: 8.57375
      }, {
        signals: [{
          js: [],
          delta: 7.33,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.32625,
        to: 7.33375
      }, {
        signals: [{
          js: [],
          delta: 7.73,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.72625,
        to: 7.733750000000001
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 9.27,
          assignment: 'NH'
        }],
        integration: 1,
        from: 9.26625,
        to: 9.27375
      }, {
        signals: [{
          js: [],
          delta: 6.75,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.74625,
        to: 6.75375
      }, {
        signals: [{
          js: [],
          delta: 6.1,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.0962499999999995,
        to: 6.10375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.75,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.74625,
        to: 2.75375
      }, {
        signals: [{
          js: [],
          delta: 1.61,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.6062500000000002,
        to: 1.61375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.08,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.07625,
        to: 0.08375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.64,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.63625,
        to: 3.6437500000000003
      }, {
        signals: [{
          js: [],
          delta: 1.8,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.7962500000000001,
        to: 1.80375
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.33,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.32625,
        to: 2.33375
      }, {
        signals: [],
        integration: 3,
        from: 7.1,
        to: 7.3,
        multiplicity: 'm'
      }, {
        signals: [],
        integration: 2,
        from: 7.1,
        to: 7.3,
        multiplicity: 'm'
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.96,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.93875,
        to: 0.98125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.45,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.4200000000000004,
        to: 2.48
      }],
      nucleus: '1H',
      solvent: 'CD₃CN'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.66,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 3.65625,
        to: 3.6637500000000003
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.06,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.05625,
        to: 2.06375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.19,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.18625,
        to: 2.19375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.95,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.94625,
        to: 1.9537499999999999
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.36,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.35625,
        to: 7.3637500000000005
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.27625,
        to: 1.28375
      }, {
        signals: [{
          js: [],
          delta: 2.2,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 1,
        from: 2.19625,
        to: 2.2037500000000003
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.33,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.32625,
        to: 7.33375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.64,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.63625,
        to: 3.6437500000000003
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.47,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.46625,
        to: 1.47375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.71,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.70625,
        to: 3.71375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.24,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.23625,
        to: 5.24375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.2,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.17875,
        to: 1.22125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.58,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5500000000000003,
        to: 3.61
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.67,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.66625,
        to: 3.67375
      }, {
        signals: [{
          js: [],
          delta: 3.62,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.61625,
        to: 3.6237500000000002
      }, {
        signals: [{
          js: [],
          delta: 3.41,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.40625,
        to: 3.4137500000000003
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.86,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.85625,
        to: 7.8637500000000005
      }, {
        signals: [{
          js: [],
          delta: 2.98,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.97625,
        to: 2.98375
      }, {
        signals: [{
          js: [],
          delta: 2.88,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.8762499999999998,
        to: 2.88375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.76,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.7562499999999996,
        to: 3.76375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.4,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.3962499999999998,
        to: 3.40375
      }, {
        signals: [{
          js: [],
          delta: 3.61,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.6062499999999997,
        to: 3.61375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.85,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.84625,
        to: 0.85375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.22,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.19875,
        to: 1.24125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.71,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.68,
        to: 3.7399999999999998
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.03,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 2.0262499999999997,
        to: 2.03375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.14,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.109999999999999,
        to: 4.17
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.26,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.23875,
        to: 1.28125
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.4,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.39625,
        to: 5.4037500000000005
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.72,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.71625,
        to: 3.7237500000000003
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.88,
        to: 0.94,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.33,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.3262500000000002,
        to: 1.33375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.24,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.23625,
        to: 2.2437500000000004
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.91,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.88875,
        to: 0.93125
      }, {
        signals: [{
          js: [],
          delta: 1.31,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.3062500000000001,
        to: 1.31375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.08,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.07625,
        to: 0.08375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.63,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.614375,
        to: 2.645625
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.53,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.52625,
        to: 4.53375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.61,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.60625,
        to: 7.6137500000000005
      }, {
        signals: [{
          js: [],
          delta: 7.03,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.02625,
        to: 7.03375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.18,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.17625,
        to: 0.18375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.44,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.43625,
        to: 3.44375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.27625,
        to: 4.28375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.87875,
        to: 0.92125
      }, {
        signals: [{
          js: [],
          delta: 1.33,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.3262500000000002,
        to: 1.33375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.878,
        to: 0.922
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.33,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2715,
        to: 1.3885
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.2,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.18875,
        to: 1.21125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 4.05,
          assignment: 'CH'
        }],
        integration: 1,
        from: 4.00125,
        to: 4.09875
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.7,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6844999999999999,
        to: 1.7155
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.93,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.913749999999999,
        to: 4.94625
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.03,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 5.005,
        to: 5.055000000000001
      }, {
        signals: [{
          js: [],
          delta: 5.87,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.86625,
        to: 5.87375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.45,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.44625,
        to: 8.45375
      }, {
        signals: [{
          js: [],
          delta: 7.4,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.39625,
        to: 7.4037500000000005
      }, {
        signals: [{
          js: [],
          delta: 7.82,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.81625,
        to: 7.82375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 6.84,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.83625,
        to: 6.84375
      }, {
        signals: [{
          js: [],
          delta: 6.24,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.23625,
        to: 6.24375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.11,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.1062499999999997,
        to: 3.11375
      }, {
        signals: [{
          js: [],
          delta: 1.93,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.92625,
        to: 1.9337499999999999
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.16,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.15625,
        to: 0.16375
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.78,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.7762499999999997,
        to: 3.78375
      }, {
        signals: [{
          js: [],
          delta: 1.91,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.90625,
        to: 1.9137499999999998
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.33,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.32625,
        to: 2.33375
      }, {
        signals: [],
        integration: 3,
        from: 7.1,
        to: 7.3,
        multiplicity: 'm'
      }, {
        signals: [],
        integration: 2,
        from: 7.1,
        to: 7.3,
        multiplicity: 'm'
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.31,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.28875,
        to: 1.33125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.12,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.0900000000000003,
        to: 3.15
      }],
      nucleus: '1H',
      solvent: 'TFE-d₃'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.87,
          multiplicity: 's',
          assignment: 'OH'
        }],
        integration: 2,
        from: 4.86625,
        to: 4.87375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.99,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.98625,
        to: 1.99375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.15,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.1462499999999998,
        to: 2.15375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.03,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.0262499999999997,
        to: 2.03375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.33,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 6,
        from: 7.32625,
        to: 7.33375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.4,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.39625,
        to: 1.4037499999999998
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.9,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.89625,
        to: 7.9037500000000005
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.64,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.63625,
        to: 3.6437500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.45,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 12,
        from: 1.44625,
        to: 1.4537499999999999
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.78,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.7762499999999997,
        to: 3.78375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.49,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 5.48625,
        to: 5.49375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.18,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.15875,
        to: 1.20125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.49,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.4600000000000004,
        to: 3.52
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.61,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.6062499999999997,
        to: 3.61375
      }, {
        signals: [{
          js: [],
          delta: 3.58,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.57625,
        to: 3.58375
      }, {
        signals: [{
          js: [],
          delta: 3.35,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.34625,
        to: 3.3537500000000002
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.97,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.96625,
        to: 7.97375
      }, {
        signals: [{
          js: [],
          delta: 2.99,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.98625,
        to: 2.9937500000000004
      }, {
        signals: [{
          js: [],
          delta: 2.86,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.8562499999999997,
        to: 2.86375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.66,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.65625,
        to: 3.6637500000000003
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.35,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.34625,
        to: 3.3537500000000002
      }, {
        signals: [{
          js: [],
          delta: 3.52,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.51625,
        to: 3.52375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.85,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.84625,
        to: 0.85375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.19,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.16875,
        to: 1.21125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.6,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.5700000000000003,
        to: 3.63
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.01,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 2.0062499999999996,
        to: 2.01375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.09,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.06,
        to: 4.12
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.24,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.21875,
        to: 1.26125
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.39,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.3862499999999995,
        to: 5.39375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.59,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5862499999999997,
        to: 3.59375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [{
        signals: [],
        integration: 6,
        from: 0.86,
        to: 0.93,
        multiplicity: 'm'
      }, {
        signals: [{
          js: [],
          delta: 1.29,
          multiplicity: 'br s',
          assignment: 'CH₂'
        }],
        integration: 10,
        from: 1.2862500000000001,
        to: 1.29375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.19,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.18625,
        to: 2.19375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.87875,
        to: 0.92125
      }, {
        signals: [{
          js: [],
          delta: 1.29,
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 1.2862500000000001,
        to: 1.29375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.07,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.06625,
        to: 0.07375000000000001
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.64,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.624375,
        to: 2.655625
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.56,
          multiplicity: 's',
          assignment: 'H₂'
        }],
        integration: 2,
        from: 4.5562499999999995,
        to: 4.56375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.67,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.66625,
        to: 7.67375
      }, {
        signals: [{
          js: [],
          delta: 7.05,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.04625,
        to: 7.05375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.2,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.19625,
        to: 0.20375000000000001
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.34,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.3362499999999997,
        to: 3.34375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.34,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.33625,
        to: 4.34375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.9,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.87875,
        to: 0.92125
      }, {
        signals: [{
          js: [],
          delta: 1.29,
          assignment: 'CH₂'
        }],
        integration: 6,
        from: 1.2862500000000001,
        to: 1.29375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.91,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.888,
        to: 0.932
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.34,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2815,
        to: 1.3985
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.5,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.48875,
        to: 1.51125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 3.92,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.87125,
        to: 3.96875
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.7,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6844999999999999,
        to: 1.7155
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.91,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.89375,
        to: 4.9262500000000005
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.01,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 4.984999999999999,
        to: 5.035
      }, {
        signals: [{
          js: [],
          delta: 5.82,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.81625,
        to: 5.82375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.53,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.52625,
        to: 8.53375
      }, {
        signals: [{
          js: [],
          delta: 7.44,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.43625,
        to: 7.4437500000000005
      }, {
        signals: [{
          js: [],
          delta: 7.85,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.8462499999999995,
        to: 7.85375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 6.72,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.71625,
        to: 6.72375
      }, {
        signals: [{
          js: [],
          delta: 6.08,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.07625,
        to: 6.08375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.8,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 2.7962499999999997,
        to: 2.80375
      }, {
        signals: [{
          js: [],
          delta: 1.72,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.71625,
        to: 1.72375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.1,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.09625,
        to: 0.10375000000000001
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.71,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.70625,
        to: 3.71375
      }, {
        signals: [{
          js: [],
          delta: 1.87,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.8662500000000002,
        to: 1.87375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.32,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.3162499999999997,
        to: 2.32375
      }, {
        signals: [{
          js: [],
          delta: 7.16,
          assignment: 'CH(2,4,6)'
        }],
        integration: 3,
        from: 7.15625,
        to: 7.16375
      }, {
        signals: [{
          js: [],
          delta: 7.16,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.15625,
        to: 7.16375
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.05,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.02875,
        to: 1.07125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.58,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.5500000000000003,
        to: 2.61
      }],
      nucleus: '1H',
      solvent: 'CD₃OD'
    }, {
      names: ['water'],
      smiles: 'O',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['acetic acid'],
      smiles: 'CC(=O)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.08,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.07625,
        to: 2.08375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['acetone'],
      smiles: 'CC(=O)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.22,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 2.21625,
        to: 2.2237500000000003
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['acetonitrile'],
      smiles: 'CC#N',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.06,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.05625,
        to: 2.06375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['benzene'],
      smiles: 'c1ccccc1',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['tert -butyl alcohol'],
      smiles: 'CC(C)(C)O',
      ranges: [{
        signals: [{
          js: [],
          delta: 1.24,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 9,
        from: 1.23625,
        to: 1.24375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['chloroform'],
      smiles: 'ClC(Cl)Cl',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['18-crown-6'],
      smiles: 'C1COCCOCCOCCOCCOCCO1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.8,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 24,
        from: 3.7962499999999997,
        to: 3.80375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['cyclohexane'],
      smiles: 'C1CCCCC1',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['1,2-dichloroethane'],
      smiles: 'ClCCCl',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['dichloromethane'],
      smiles: 'ClCCl',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.17,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.14875,
        to: 1.19125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.56,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.5300000000000002,
        to: 3.59
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['diglyme'],
      smiles: 'COCCOCCOC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.67,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.66625,
        to: 3.67375
      }, {
        signals: [{
          js: [],
          delta: 3.61,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.6062499999999997,
        to: 3.61375
      }, {
        signals: [{
          js: [],
          delta: 3.37,
          multiplicity: 's',
          assignment: 'OCH₃'
        }],
        integration: 6,
        from: 3.36625,
        to: 3.3737500000000002
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['dimethylformamide'],
      smiles: 'C(=O)N(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.92,
          multiplicity: 's',
          assignment: 'CH'
        }],
        integration: 1,
        from: 7.91625,
        to: 7.92375
      }, {
        signals: [{
          js: [],
          delta: 3.01,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.0062499999999996,
        to: 3.01375
      }, {
        signals: [{
          js: [],
          delta: 2.85,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 2.84625,
        to: 2.8537500000000002
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['1,4-dioxane'],
      smiles: 'C1COCCOC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.75,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 8,
        from: 3.74625,
        to: 3.75375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['DME', 'diethyl ether'],
      smiles: 'CCOCC',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.37,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 3.36625,
        to: 3.3737500000000002
      }, {
        signals: [{
          js: [],
          delta: 3.6,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.59625,
        to: 3.6037500000000002
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['ethane'],
      smiles: 'CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.82,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.8162499999999999,
        to: 0.82375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['ethanol'],
      smiles: 'CCO',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.17,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.14875,
        to: 1.19125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 3.65,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 3.62,
        to: 3.6799999999999997
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['ethyl acetate'],
      smiles: 'CC(=O)CC',
      ranges: [{
        signals: [{
          js: [],
          delta: 2.07,
          multiplicity: 's',
          assignment: 'CH₃CO'
        }],
        integration: 3,
        from: 2.0662499999999997,
        to: 2.07375
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 4.14,
          assignment: 'CH₂CH₃'
        }],
        integration: 2,
        from: 4.109999999999999,
        to: 4.17
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 1.24,
          assignment: 'CH₂CH₃'
        }],
        integration: 3,
        from: 1.21875,
        to: 1.26125
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['ethylene'],
      smiles: 'C=C',
      ranges: [{
        signals: [{
          js: [],
          delta: 5.44,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 5.43625,
        to: 5.4437500000000005
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['ethylene glycol'],
      smiles: 'OCCO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.65,
          multiplicity: 's',
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 3.6462499999999998,
        to: 3.65375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['H greaseᶠ'],
      smiles: '',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['hexamethylbenzene'],
      smiles: 'CC1=C(C(=C(C(=C1C)C)C)C)C',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['n-hexane'],
      smiles: 'CCCCCC',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['HMDSO'],
      smiles: 'C[Si](C)(C)O[Si](C)(C)C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.28,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 0.27625000000000005,
        to: 0.28375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['HMPA'],
      smiles: 'CN(C)P(=O)(N(C)C)N(C)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 9.5,
            multiplicity: 'd'
          }],
          delta: 2.61,
          assignment: 'CH₃'
        }],
        integration: 18,
        from: 2.594375,
        to: 2.625625
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['hydrogen'],
      smiles: '',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['imidazole'],
      smiles: 'C1=CN=CN1',
      ranges: [{
        signals: [{
          js: [],
          delta: 7.78,
          multiplicity: 's',
          assignment: 'CH(2)'
        }],
        integration: 1,
        from: 7.77625,
        to: 7.78375
      }, {
        signals: [{
          js: [],
          delta: 7.14,
          multiplicity: 's',
          assignment: 'CH(4,5)'
        }],
        integration: 2,
        from: 7.1362499999999995,
        to: 7.14375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['methane'],
      smiles: 'C',
      ranges: [{
        signals: [{
          js: [],
          delta: 0.18,
          multiplicity: 's',
          assignment: 'CH₄'
        }],
        integration: 4,
        from: 0.17625,
        to: 0.18375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['methanol'],
      smiles: 'CO',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.34,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 3.3362499999999997,
        to: 3.34375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['nitromethane'],
      smiles: 'C[N+](=O)[O-]',
      ranges: [{
        signals: [{
          js: [],
          delta: 4.4,
          multiplicity: 's',
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 4.39625,
        to: 4.4037500000000005
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['n-pentane'],
      smiles: 'CCCCC',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['propane'],
      smiles: 'CCC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 't'
          }],
          delta: 0.88,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.858,
        to: 0.902
      }, {
        signals: [{
          js: [{
            coupling: 7.3,
            multiplicity: 'sept'
          }],
          delta: 1.3,
          assignment: 'CH₂'
        }],
        integration: 2,
        from: 1.2415,
        to: 1.3585
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['2-propanol'],
      smiles: 'CC(O)C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'd'
          }],
          delta: 1.17,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 1.15875,
        to: 1.18125
      }, {
        signals: [{
          js: [{
            coupling: 6,
            multiplicity: 'sept'
          }],
          delta: 4.02,
          assignment: 'CH'
        }],
        integration: 1,
        from: 3.9712499999999995,
        to: 4.06875
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['propylene'],
      smiles: 'CC=C',
      ranges: [{
        signals: [{
          js: [{
            coupling: 6.4,
            multiplicity: 'd'
          }, {
            coupling: 1.5,
            multiplicity: 't'
          }],
          delta: 1.7,
          assignment: 'CH₃'
        }],
        integration: 3,
        from: 1.6844999999999999,
        to: 1.7155
      }, {
        signals: [{
          js: [{
            coupling: 10,
            multiplicity: 'd'
          }],
          delta: 4.95,
          assignment: 'CH₂(1)'
        }],
        integration: 1,
        from: 4.93375,
        to: 4.9662500000000005
      }, {
        signals: [{
          js: [{
            coupling: 17,
            multiplicity: 'd'
          }],
          delta: 5.06,
          assignment: 'CH₂(2)'
        }],
        integration: 1,
        from: 5.034999999999999,
        to: 5.085
      }, {
        signals: [{
          js: [],
          delta: 5.9,
          assignment: 'CH'
        }],
        integration: 1,
        from: 5.89625,
        to: 5.9037500000000005
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['pyridine'],
      smiles: 'C1=CC=NC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 8.52,
          assignment: 'CH(2,6)'
        }],
        integration: 2,
        from: 8.51625,
        to: 8.52375
      }, {
        signals: [{
          js: [],
          delta: 7.45,
          assignment: 'CH(3,5)'
        }],
        integration: 2,
        from: 7.44625,
        to: 7.45375
      }, {
        signals: [{
          js: [],
          delta: 7.87,
          assignment: 'CH(4)'
        }],
        integration: 1,
        from: 7.86625,
        to: 7.87375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['pyrrole'],
      smiles: 'C1=CNC=C1',
      ranges: [{
        signals: [{
          js: [],
          delta: 6.93,
          assignment: 'CH(2,5)'
        }],
        integration: 2,
        from: 6.92625,
        to: 6.93375
      }, {
        signals: [{
          js: [],
          delta: 6.26,
          assignment: 'CH(3,4)'
        }],
        integration: 2,
        from: 6.25625,
        to: 6.26375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['pyrrolidine'],
      smiles: 'C1CCNC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.07,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.0662499999999997,
        to: 3.07375
      }, {
        signals: [{
          js: [],
          delta: 1.87,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.8662500000000002,
        to: 1.87375
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['silicone grease'],
      smiles: '',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['tetrahydrofuran'],
      smiles: 'C1COCC1',
      ranges: [{
        signals: [{
          js: [],
          delta: 3.74,
          assignment: 'CH₂(2,5)'
        }],
        integration: 4,
        from: 3.73625,
        to: 3.7437500000000004
      }, {
        signals: [{
          js: [],
          delta: 1.88,
          assignment: 'CH₂(3,4)'
        }],
        integration: 4,
        from: 1.87625,
        to: 1.8837499999999998
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['toluene'],
      smiles: 'Cc1ccccc1',
      ranges: [],
      nucleus: '1H',
      solvent: 'D₂O'
    }, {
      names: ['triethylamine'],
      smiles: 'CCN(CC)CC',
      ranges: [{
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 't'
          }],
          delta: 0.99,
          assignment: 'CH₃'
        }],
        integration: 6,
        from: 0.96875,
        to: 1.01125
      }, {
        signals: [{
          js: [{
            coupling: 7,
            multiplicity: 'q'
          }],
          delta: 2.57,
          assignment: 'CH₂'
        }],
        integration: 4,
        from: 2.54,
        to: 2.5999999999999996
      }],
      nucleus: '1H',
      solvent: 'D₂O'
    }];

    function getShortestPath(options) {
      let {
        currUnAssCol,
        dualVariableForColumns,
        dualVariableForRows,
        rowAssignments,
        columnAssignments,
        matrix
      } = options;
      let nbRows = matrix.rows;
      let nbColumns = matrix.columns;
      let pred = new Float64Array(nbRows);
      let scannedColumns = new Float64Array(nbColumns);
      let scannedRows = new Float64Array(nbRows);
      let rows2Scan = Array.from(xSequentialFill({
        from: 0,
        to: nbRows - 1
      }));
      let numRows2Scan = nbRows;
      let sink = -1;
      let delta = 0;
      let curColumn = currUnAssCol;
      let shortestPathCost = new Array(nbRows).fill(Number.POSITIVE_INFINITY);

      while (sink === -1) {
        scannedColumns[curColumn] = 1;
        let minVal = Number.POSITIVE_INFINITY;
        let closestRowScan = -1;

        for (let curRowScan = 0; curRowScan < numRows2Scan; curRowScan++) {
          let curRow = rows2Scan[curRowScan];
          let reducedCost = delta + matrix.get(curRow, curColumn) - dualVariableForColumns[curColumn] - dualVariableForRows[curRow];

          if (reducedCost < shortestPathCost[curRow]) {
            pred[curRow] = curColumn;
            shortestPathCost[curRow] = reducedCost;
          }

          if (shortestPathCost[curRow] < minVal) {
            minVal = shortestPathCost[curRow];
            closestRowScan = curRowScan;
          }
        }

        if (!Number.isFinite(minVal)) {
          return {
            dualVariableForColumns,
            dualVariableForRows,
            sink,
            pred
          };
        }

        let closestRow = rows2Scan[closestRowScan];
        scannedRows[closestRow] = 1;
        numRows2Scan -= 1;
        rows2Scan.splice(closestRowScan, 1);
        delta = shortestPathCost[closestRow];

        if (rowAssignments[closestRow] === -1) {
          sink = closestRow;
        } else {
          curColumn = rowAssignments[closestRow];
        }
      }

      dualVariableForColumns[currUnAssCol] += delta;

      for (let sel = 0; sel < nbColumns; sel++) {
        if (scannedColumns[sel] === 0) continue;
        if (sel === currUnAssCol) continue;
        dualVariableForColumns[sel] += delta - shortestPathCost[columnAssignments[sel]];
      }

      for (let sel = 0; sel < nbRows; sel++) {
        if (scannedRows[sel] === 0) continue;
        dualVariableForRows[sel] -= delta - shortestPathCost[sel];
      }

      return {
        sink,
        pred,
        dualVariableForColumns,
        dualVariableForRows
      };
    }

    /**
     * Implementation of Jonker-Volgenant shortest augmenting path algorithm based
     * on the publication [On implementing 2D rectangular assignment algorithms](https://doi.org/10.1109/TAES.2016.140952)
     */

    function linearSumAssignment(
    /**
     * Cost matrix
     */
    input) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      const {
        maximaze = true
      } = options;
      let matrix = Matrix.checkMatrix(input);
      let didFlip = false;

      if (matrix.columns > matrix.rows) {
        didFlip = true;
        matrix = matrix.transpose();
      }

      let nbRows = matrix.rows;
      let nbColumns = matrix.columns;
      let matrixDelta = maximaze ? matrix.max() : matrix.min();
      matrix = matrix.subtract(matrixDelta);
      if (maximaze) matrix = matrix.mul(-1);
      let rowAssignments = new Float64Array(nbRows).fill(-1);
      let columnAssignments = new Float64Array(nbColumns).fill(-1);
      let dualVariableForColumns = new Float64Array(nbColumns);
      let dualVariableForRows = new Float64Array(nbRows);

      for (let currUnAssCol = 0; currUnAssCol < nbColumns; currUnAssCol++) {
        let currentAugmenting = getShortestPath({
          matrix,
          currUnAssCol,
          dualVariableForColumns,
          dualVariableForRows,
          rowAssignments,
          columnAssignments
        });
        let {
          sink,
          pred
        } = currentAugmenting;

        if (sink === -1) {
          return {
            rowAssignments,
            columnAssignments,
            gain: -1,
            dualVariableForColumns,
            dualVariableForRows
          };
        }

        dualVariableForColumns = currentAugmenting.dualVariableForColumns;
        dualVariableForRows = currentAugmenting.dualVariableForRows;
        let j = sink;

        for (let i = pred[j]; true; i = pred[j]) {
          rowAssignments[j] = i;
          let h = columnAssignments[i];
          columnAssignments[i] = j;
          j = h;
          if (i === currUnAssCol) break;
        }
      }

      let gain = 0;

      for (let curCol = 0; curCol < nbColumns; curCol++) {
        gain += matrix.get(columnAssignments[curCol], curCol);
      }

      gain = (maximaze ? -1 : 1) * gain + matrixDelta * nbColumns;

      if (didFlip) {
        [columnAssignments, rowAssignments] = [rowAssignments, columnAssignments];
        [dualVariableForColumns, dualVariableForRows] = [dualVariableForRows, dualVariableForColumns];
      }

      return {
        rowAssignments,
        columnAssignments,
        gain,
        dualVariableForColumns,
        dualVariableForRows
      };
    }

    const {
      stringify,
      parse
    } = JSON;
    function cloneArray(data) {
      return parse(stringify(data));
    }

    function solventSuppression(peakList, solvent) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      const peaks = cloneArray(peakList).sort((a, b) => a.x - b.x);
      const xValues = peaks.map(peak => peak.x);
      const {
        markSolventPeaks = false,
        solventZoneExtension = 1.2
      } = options;

      for (const solventSignal of solvent) {
        let solventXYPeaks = solventSignal.peaks ? solventSignal.peaks : getSolventPeaks(solventSignal);
        solventXYPeaks.sort((a, b) => a.x - b.x);
        let upIndex = xFindClosestIndex(xValues, solventXYPeaks[solventXYPeaks.length - 1].x + solventZoneExtension);
        let lowIndex = xFindClosestIndex(xValues, solventXYPeaks[0].x - solventZoneExtension);
        const nearPeaks = peaks.filter((peak, index) => index >= lowIndex && index <= upIndex);
        const amplitudeResiduals = [];
        const deltaResiduals = [];
        const positionResiduals = [];

        for (let peak of nearPeaks) {
          const {
            peaks: shiftedSolventPeaks,
            delta: currentDelta
          } = getShiftedSolventPeaks(peak, solventSignal, solventXYPeaks);
          const closestPeaks = getClosestPeaks(shiftedSolventPeaks, nearPeaks);
          let deltaResidual = 0;
          let amplitudeResidual = 0;
          let positionResidual = 0;

          for (let i = 0; i < closestPeaks.length; i++) {
            amplitudeResidual += Math.abs(shiftedSolventPeaks[i].y - closestPeaks[i].y);
            deltaResidual += Math.abs(shiftedSolventPeaks[i].x - closestPeaks[i].x);
          }

          if (closestPeaks.length === 0) {
            deltaResidual = Number.MAX_SAFE_INTEGER;
            amplitudeResidual = Number.MAX_SAFE_INTEGER;
            positionResidual = Number.MAX_SAFE_INTEGER;
          } else {
            positionResidual = gaussianFct(Math.abs(solventSignal.delta - currentDelta), 0.5);
          }

          amplitudeResiduals.push(amplitudeResidual);
          deltaResiduals.push(deltaResidual);
          positionResiduals.push(positionResidual);
        }

        const [maxAmplitude, maxDelta, maxPosition] = [amplitudeResiduals, deltaResiduals, positionResiduals].map(data => {
          const max = xMaxValue(data);
          return max === 0 ? 1 : max;
        });
        let minIndex = -1;
        let minScore = Number.MAX_SAFE_INTEGER;

        for (let i = 0; i < deltaResiduals.length; i++) {
          const value = (amplitudeResiduals[i] / maxAmplitude + deltaResiduals[i] / maxDelta + 1 - positionResiduals[i] / maxPosition) / 3;

          if (minScore > value) {
            minIndex = i;
            minScore = value;
          }
        }

        if (minScore < 0 || minIndex < 0) {
          return peaks;
        }

        const {
          peaks: shiftedSolventPeaks
        } = getShiftedSolventPeaks(nearPeaks[minIndex], solventSignal, solventXYPeaks);
        const diff = getDiffMatrix(shiftedSolventPeaks, nearPeaks);
        const {
          rowAssignments,
          gain
        } = linearSumAssignment(diff, {
          maximaze: false
        });

        if (gain < 0) {
          return peaks;
        }

        if (markSolventPeaks) {
          for (let index of rowAssignments) {
            peaks[index + lowIndex].kind = 'solvent';
          }
        } else {
          rowAssignments.sort((a, b) => b - a);

          for (let index of rowAssignments) {
            peaks.splice(index + lowIndex, 1);
          }
        }
      }

      return peaks;
    }

    function getSolventPeaks(signal) {
      let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      let signals = addDummySignals([signal]);
      let spinSystem = signalsToSpinSystem(signals);
      const {
        frequency = 400,
        maxClusterSize = 8
      } = options;
      spinSystem.clusters = splitSpinSystem(spinSystem, {
        frequency,
        maxClusterSize
      });
      const peaks = simulateXYPeaks(spinSystem);
      return peaks.filter(peak => peak.x < 1000);
    }

    function getShiftedSolventPeaks(peak, solventSignal, solventXYPeaks) {
      const shiftedSolventPeaks = JSON.parse(JSON.stringify(solventXYPeaks)); // shift x values of solventPeaks to center it to the current peak.

      let deltaPPM = peak.x - solventSignal.delta;

      if (solventXYPeaks.length > 1 && solventXYPeaks.length % 2 === 0) {
        deltaPPM += solventXYPeaks[0].x;
      }

      const maxIntensity = shiftedSolventPeaks.reduce((max, current) => current.y > max ? current.y : max, shiftedSolventPeaks[0].y);
      let currentDelta = 0;

      for (let shiftedSolventPeak of shiftedSolventPeaks) {
        shiftedSolventPeak.x += deltaPPM;
        shiftedSolventPeak.y /= maxIntensity;
        currentDelta += shiftedSolventPeak.x;
      }

      return {
        peaks: shiftedSolventPeaks,
        delta: currentDelta / shiftedSolventPeaks.length
      };
    }

    function getClosestPeaks(shiftedSolventPeaks, nearPeaks) {
      const diff = getDiffMatrix(shiftedSolventPeaks, nearPeaks);
      const {
        rowAssignments,
        gain
      } = linearSumAssignment(diff, {
        maximaze: false
      });
      if (gain === -1) return [];
      const assignmentPeaks = [];
      let maxValue = Number.MIN_SAFE_INTEGER;

      for (let index of rowAssignments) {
        if (maxValue < nearPeaks[index].y) maxValue = nearPeaks[index].y;
        assignmentPeaks.push({ ...nearPeaks[index]
        });
      }

      assignmentPeaks.forEach((peak, i, arr) => arr[i].y /= maxValue);
      return assignmentPeaks;
    }

    function getDiffMatrix(rows, columns) {
      const nbColumns = columns.length;
      const nbRows = rows.length;
      const diff = new Matrix(nbRows, nbColumns);

      for (let r = 0; r < nbRows; r++) {
        for (let c = 0; c < nbColumns; c++) {
          diff.set(r, c, Math.abs(rows[r].x - columns[c].x));
        }
      }

      return diff;
    }

    function markSolventPeaks(input, solventSignals) {
      let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      const {
        frequency = 400
      } = options;
      const ranges = addIDs(cloneArray(input));
      let peakList = [];

      for (const range of ranges) {
        const rangeID = range.id;

        for (const signal of range.signals || []) {
          const signalID = signal.id;

          for (let peak of signal.peaks || []) {
            peakList.push({ ...peak,
              rangeID,
              signalID
            });
          }
        }
      }

      const peaks = solventSuppression(peakList, solventSignals, {
        markSolventPeaks: true
      });
      const signalsWithSolvent = getSignalIDsWithSolvent(peaks);

      for (let range of ranges) {
        if (!range.signals) continue;

        for (let signal of range.signals) {
          if (!signalsWithSolvent.includes(signal.id)) continue;
          const signalPeaks = [];
          const solventSignalPeaks = [];

          for (let peak of peaks) {
            if (peak.signalID === signal.id) {
              const {
                signalID,
                rangeID,
                ...newPeak
              } = peak;

              if (peak.kind === 'solvent') {
                solventSignalPeaks.push(newPeak);
              } else {
                signalPeaks.push(newPeak);
              }
            }
          }

          const newSignals = signalPeaks.length > 0 ? detectSignals({
            x: [],
            y: []
          }, signalPeaks, {
            integralType: 'peak',
            frequency
          }) : [];
          solventSignalPeaks.sort((a, b) => a.x - b.x);
          const lowPPMValue = solventSignalPeaks[0].x;
          const highPPMValue = solventSignalPeaks[solventSignalPeaks.length - 1].x;
          const newSolventSignals = detectSignals({
            x: [],
            y: []
          }, solventSignalPeaks, {
            integralType: 'peak',
            frequencyCluster: (highPPMValue - lowPPMValue) * frequency,
            frequency
          });
          range.signals = [...adaptSignals(newSignals), ...adaptSignals(newSolventSignals), ...range.signals.filter(currSignal => currSignal.id !== signal.id)];
        }
      }

      return ranges;
    }

    function getSignalIDsWithSolvent(solventPeaks) {
      const uniqueSignalID = new Set();

      for (let peak of solventPeaks) {
        if (peak.kind !== 'solvent') continue;
        uniqueSignalID.add(peak.signalID);
      }

      return Array.from(uniqueSignalID);
    }

    function adaptSignals(signals) {
      const newSignals = [];

      for (let signal of signals) {
        const signalResult = {
          id: v4(),
          delta: signal.delta,
          kind: signal.kind || 'signal',
          multiplicity: signal.multiplicity,
          integration: signal.integralData.value
        };
        signalResult.peaks = signal.peaks.map(peak => {
          const newResult = {
            y: peak.intensity,
            ...peak
          };
          delete newResult.intensity;
          return newResult;
        });
        signalResult.js = signal.nmrJs || [];
        newSignals.push(signalResult);
      }

      return newSignals;
    }

    /**
     * pure function that applies a window function to the input data.
     */
    function applyWindow(data, options) {
      const dataLength = data.length;
      const {
        windowData,
        start = 0,
        length = dataLength,
        pointsToShift = 0,
        output = new Float64Array(data)
      } = options;
      const firstEndPoint = Math.min(start + length, dataLength - pointsToShift);

      for (let i = start, j = 0; i < firstEndPoint; i++) {
        output[i] *= windowData[j++];
      }

      for (let i = dataLength - 1, j = 0; i > dataLength - pointsToShift - 1; i--) {
        output[i] *= windowData[j++];
      }

      return output;
    }

    function exponential(options) {
      const {
        lb,
        dw
      } = options;
      const coefExp = -lb * Math.PI * dw;
      return i => Math.exp(coefExp * i);
    }

    function lorentzToGauss(options) {
      const {
        dw,
        length,
        gaussianHz = 0,
        exponentialHz = 0,
        center = 0
      } = options;

      if (center > 1 || center < 0) {
        throw new Error('The center of gaussian shape should be inside of the window function: 0 - 1');
      }

      const C5 = Math.pow(0.6 * Math.PI * gaussianHz * dw, 2);
      const C2 = center * (length - 1);
      const C6 = Math.PI * dw * exponentialHz;
      return i => Math.exp(i * C6 - Math.pow(C2 - i, 2) * C5);
    }

    function getFunction(shape) {
      const {
        kind,
        options
      } = shape;

      switch (kind) {
        case 'exponential':
          return exponential(options);

        case 'lorentzToGauss':
          return lorentzToGauss(options);

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

    /**
     * generate and scale the data of a window function
     */
    function getData(func, length) {
      const data = new Float64Array(length);
      let max = Number.MIN_SAFE_INTEGER;

      for (let i = 0; i < length; i++) {
        const value = func(i);
        data[i] = value;
        if (value > max) max = value;
      }

      for (let i = 0; i < length; i++) data[i] /= max;

      return data;
    }

    function compose(shapeOptions) {
      const {
        length: dataLength,
        shapes = []
      } = shapeOptions;
      let data = new Float64Array(dataLength).fill(1);
      shapes.forEach(options => {
        const {
          shape,
          start = 0
        } = options;
        const {
          options: shapeOptions
        } = shape;
        const length = 'length' in shapeOptions ? shapeOptions.length : dataLength - start;
        const windowData = getData(getFunction(shape), length);
        applyWindow(data, {
          windowData,
          length,
          start,
          output: data
        });
      });
      return data;
    }

    function apodization(data, options) {
      const {
        compose: composeOptions,
        pointsToShift
      } = options;
      const windowData = compose(composeOptions);
      const applyWindowOptions = {
        windowData,
        pointsToShift
      };
      const re = applyWindow(data.re, applyWindowOptions);
      const im = applyWindow(data.im, applyWindowOptions);
      return {
        re,
        im,
        windowData
      };
    }

    exports.apodization = apodization;
    exports.carbonImpurities = carbonImpurities;
    exports.couplingPatterns = couplingPatterns;
    exports.get13CAssignments = get13CAssignments;
    exports.get1HAssignments = get1HAssignments;
    exports.getAssignments = getAssignments;
    exports.getDatabase = getDatabase;
    exports.getFrequency = getFrequency;
    exports.gyromagneticRatio = gyromagneticRatio;
    exports.impurities = impurities;
    exports.markSolventPeaks = markSolventPeaks;
    exports.optimizeSignals = optimizeSignals;
    exports.peakToXY = peakToXY;
    exports.peaksFilterImpurities = peaksFilterImpurities;
    exports.peaksToXY = peaksToXY;
    exports.predictAll = predictAll;
    exports.predictAllSpectra = predictAllSpectra;
    exports.predictCOSY = predictCOSY;
    exports.predictCarbon = predictCarbon;
    exports.predictHMBC = predictHMBC;
    exports.predictHSQC = predictHSQC;
    exports.predictProton = predictProton;
    exports.protonImpurities = protonImpurities;
    exports.rangeFromSignal = rangeFromSignal;
    exports.rangesToACS = rangesToACS;
    exports.rangesToXY = rangesToXY;
    exports.resurrect = resurrect;
    exports.signals2DToZ = signals2DToZ;
    exports.signalsToRanges = signalsToRanges;
    exports.signalsToXY = signalsToXY;
    exports.solventSuppression = solventSuppression;
    exports.xyAutoPeaksPicking = xyAutoPeaksPicking;
    exports.xyAutoRangesPicking = xyAutoRangesPicking;
    exports.xyPeaksOptimization = xyPeaksOptimization;
    exports.xyzAutoZonesPicking = xyzAutoZonesPicking;
    exports.xyzJResAnalyzer = xyzJResAnalyzer;

    Object.defineProperty(exports, '__esModule', { value: true });

}));
//# sourceMappingURL=nmr-processing.js.map
