/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
*/

'use strict';

var obsidian = require('obsidian');
var require$$0 = require('stream');

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

var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0);

/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */

function __rest(s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
}

function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

class ResizeableBuffer{
  constructor(size=100){
    this.size = size;
    this.length = 0;
    this.buf = Buffer.alloc(size);
  }
  prepend(val){
    if(Buffer.isBuffer(val)){
      const length = this.length + val.length;
      if(length >= this.size){
        this.resize();
        if(length >= this.size){
          throw Error('INVALID_BUFFER_STATE')
        }
      }
      const buf = this.buf;
      this.buf = Buffer.alloc(this.size);
      val.copy(this.buf, 0);
      buf.copy(this.buf, val.length);
      this.length += val.length;
    }else {
      const length = this.length++;
      if(length === this.size){
        this.resize();
      }
      const buf = this.clone();
      this.buf[0] = val;
      buf.copy(this.buf,1, 0, length);
    }
  }
  append(val){
    const length = this.length++;
    if(length === this.size){
      this.resize();
    }
    this.buf[length] = val;
  }
  clone(){
    return Buffer.from(this.buf.slice(0, this.length))
  }
  resize(){
    const length = this.length;
    this.size = this.size * 2;
    const buf = Buffer.alloc(this.size);
    this.buf.copy(buf,0, 0, length);
    this.buf = buf;
  }
  toString(encoding){
    if(encoding){
      return this.buf.slice(0, this.length).toString(encoding)
    }else {
      return Uint8Array.prototype.slice.call(this.buf.slice(0, this.length))
    }
  }
  toJSON(){
    return this.toString('utf8')
  }
  reset(){
    this.length = 0;
  }
}

var ResizeableBuffer_1 = ResizeableBuffer;

/*
CSV Parse

Please look at the [project documentation](https://csv.js.org/parse/) for
additional information.
*/

const { Transform } = require$$0__default["default"];


// white space characters
// https://en.wikipedia.org/wiki/Whitespace_character
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes#Types
// \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff
const tab = 9;
const nl = 10; // \n, 0x0A in hexadecimal, 10 in decimal
const np = 12;
const cr = 13; // \r, 0x0D in hexadécimal, 13 in decimal
const space = 32;
const boms = {
  // Note, the following are equals:
  // Buffer.from("\ufeff")
  // Buffer.from([239, 187, 191])
  // Buffer.from('EFBBBF', 'hex')
  'utf8': Buffer.from([239, 187, 191]),
  // Note, the following are equals:
  // Buffer.from "\ufeff", 'utf16le
  // Buffer.from([255, 254])
  'utf16le': Buffer.from([255, 254])
};

class Parser extends Transform {
  constructor(opts = {}){
    super({...{readableObjectMode: true}, ...opts, encoding: null});
    this.__originalOptions = opts;
    this.__normalizeOptions(opts);
  }
  __normalizeOptions(opts){
    const options = {};
    // Merge with user options
    for(let opt in opts){
      options[underscore(opt)] = opts[opt];
    }
    // Normalize option `encoding`
    // Note: defined first because other options depends on it
    // to convert chars/strings into buffers.
    if(options.encoding === undefined || options.encoding === true){
      options.encoding = 'utf8';
    }else if(options.encoding === null || options.encoding === false){
      options.encoding = null;
    }else if(typeof options.encoding !== 'string' && options.encoding !== null){
      throw new CsvError('CSV_INVALID_OPTION_ENCODING', [
        'Invalid option encoding:',
        'encoding must be a string or null to return a buffer,',
        `got ${JSON.stringify(options.encoding)}`
      ], options)
    }
    // Normalize option `bom`
    if(options.bom === undefined || options.bom === null || options.bom === false){
      options.bom = false;
    }else if(options.bom !== true){
      throw new CsvError('CSV_INVALID_OPTION_BOM', [
        'Invalid option bom:', 'bom must be true,',
        `got ${JSON.stringify(options.bom)}`
      ], options)
    }
    // Normalize option `cast`
    let fnCastField = null;
    if(options.cast === undefined || options.cast === null || options.cast === false || options.cast === ''){
      options.cast = undefined;
    }else if(typeof options.cast === 'function'){
      fnCastField = options.cast;
      options.cast = true;
    }else if(options.cast !== true){
      throw new CsvError('CSV_INVALID_OPTION_CAST', [
        'Invalid option cast:', 'cast must be true or a function,',
        `got ${JSON.stringify(options.cast)}`
      ], options)
    }
    // Normalize option `cast_date`
    if(options.cast_date === undefined || options.cast_date === null || options.cast_date === false || options.cast_date === ''){
      options.cast_date = false;
    }else if(options.cast_date === true){
      options.cast_date = function(value){
        const date = Date.parse(value);
        return !isNaN(date) ? new Date(date) : value
      };
    }else {
      throw new CsvError('CSV_INVALID_OPTION_CAST_DATE', [
        'Invalid option cast_date:', 'cast_date must be true or a function,',
        `got ${JSON.stringify(options.cast_date)}`
      ], options)
    }
    // Normalize option `columns`
    let fnFirstLineToHeaders = null;
    if(options.columns === true){
      // Fields in the first line are converted as-is to columns
      fnFirstLineToHeaders = undefined;
    }else if(typeof options.columns === 'function'){
      fnFirstLineToHeaders = options.columns;
      options.columns = true;
    }else if(Array.isArray(options.columns)){
      options.columns = normalizeColumnsArray(options.columns);
    }else if(options.columns === undefined || options.columns === null || options.columns === false){
      options.columns = false;
    }else {
      throw new CsvError('CSV_INVALID_OPTION_COLUMNS', [
        'Invalid option columns:',
        'expect an array, a function or true,',
        `got ${JSON.stringify(options.columns)}`
      ], options)
    }
    // Normalize option `columns_duplicates_to_array`
    if(options.columns_duplicates_to_array === undefined || options.columns_duplicates_to_array === null || options.columns_duplicates_to_array === false){
      options.columns_duplicates_to_array = false;
    }else if(options.columns_duplicates_to_array !== true){
      throw new CsvError('CSV_INVALID_OPTION_COLUMNS_DUPLICATES_TO_ARRAY', [
        'Invalid option columns_duplicates_to_array:',
        'expect an boolean,',
        `got ${JSON.stringify(options.columns_duplicates_to_array)}`
      ], options)
    }else if(options.columns === false){
      throw new CsvError('CSV_INVALID_OPTION_COLUMNS_DUPLICATES_TO_ARRAY', [
        'Invalid option columns_duplicates_to_array:',
        'the `columns` mode must be activated.'
      ], options)
    }
    // Normalize option `comment`
    if(options.comment === undefined || options.comment === null || options.comment === false || options.comment === ''){
      options.comment = null;
    }else {
      if(typeof options.comment === 'string'){
        options.comment = Buffer.from(options.comment, options.encoding);
      }
      if(!Buffer.isBuffer(options.comment)){
        throw new CsvError('CSV_INVALID_OPTION_COMMENT', [
          'Invalid option comment:',
          'comment must be a buffer or a string,',
          `got ${JSON.stringify(options.comment)}`
        ], options)
      }
    }
    // Normalize option `delimiter`
    const delimiter_json = JSON.stringify(options.delimiter);
    if(!Array.isArray(options.delimiter)) options.delimiter = [options.delimiter];
    if(options.delimiter.length === 0){
      throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [
        'Invalid option delimiter:',
        'delimiter must be a non empty string or buffer or array of string|buffer,',
        `got ${delimiter_json}`
      ], options)
    }
    options.delimiter = options.delimiter.map(function(delimiter){
      if(delimiter === undefined || delimiter === null || delimiter === false){
        return Buffer.from(',', options.encoding)
      }
      if(typeof delimiter === 'string'){
        delimiter = Buffer.from(delimiter, options.encoding);
      }
      if( !Buffer.isBuffer(delimiter) || delimiter.length === 0){
        throw new CsvError('CSV_INVALID_OPTION_DELIMITER', [
          'Invalid option delimiter:',
          'delimiter must be a non empty string or buffer or array of string|buffer,',
          `got ${delimiter_json}`
        ], options)
      }
      return delimiter
    });
    // Normalize option `escape`
    if(options.escape === undefined || options.escape === true){
      options.escape = Buffer.from('"', options.encoding);
    }else if(typeof options.escape === 'string'){
      options.escape = Buffer.from(options.escape, options.encoding);
    }else if (options.escape === null || options.escape === false){
      options.escape = null;
    }
    if(options.escape !== null){
      if(!Buffer.isBuffer(options.escape)){
        throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`)
      }
    }
    // Normalize option `from`
    if(options.from === undefined || options.from === null){
      options.from = 1;
    }else {
      if(typeof options.from === 'string' && /\d+/.test(options.from)){
        options.from = parseInt(options.from);
      }
      if(Number.isInteger(options.from)){
        if(options.from < 0){
          throw new Error(`Invalid Option: from must be a positive integer, got ${JSON.stringify(opts.from)}`)
        }
      }else {
        throw new Error(`Invalid Option: from must be an integer, got ${JSON.stringify(options.from)}`)
      }
    }
    // Normalize option `from_line`
    if(options.from_line === undefined || options.from_line === null){
      options.from_line = 1;
    }else {
      if(typeof options.from_line === 'string' && /\d+/.test(options.from_line)){
        options.from_line = parseInt(options.from_line);
      }
      if(Number.isInteger(options.from_line)){
        if(options.from_line <= 0){
          throw new Error(`Invalid Option: from_line must be a positive integer greater than 0, got ${JSON.stringify(opts.from_line)}`)
        }
      }else {
        throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`)
      }
    }
    // Normalize options `ignore_last_delimiters`
    if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){
      options.ignore_last_delimiters = false;
    }else if(typeof options.ignore_last_delimiters === 'number'){
      options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters);
      if(options.ignore_last_delimiters === 0){
        options.ignore_last_delimiters = false;
      }
    }else if(typeof options.ignore_last_delimiters !== 'boolean'){
      throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [
        'Invalid option `ignore_last_delimiters`:',
        'the value must be a boolean value or an integer,',
        `got ${JSON.stringify(options.ignore_last_delimiters)}`
      ], options)
    }
    if(options.ignore_last_delimiters === true && options.columns === false){
      throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [
        'The option `ignore_last_delimiters`',
        'requires the activation of the `columns` option'
      ], options)
    }
    // Normalize option `info`
    if(options.info === undefined || options.info === null || options.info === false){
      options.info = false;
    }else if(options.info !== true){
      throw new Error(`Invalid Option: info must be true, got ${JSON.stringify(options.info)}`)
    }
    // Normalize option `max_record_size`
    if(options.max_record_size === undefined || options.max_record_size === null || options.max_record_size === false){
      options.max_record_size = 0;
    }else if(Number.isInteger(options.max_record_size) && options.max_record_size >= 0);else if(typeof options.max_record_size === 'string' && /\d+/.test(options.max_record_size)){
      options.max_record_size = parseInt(options.max_record_size);
    }else {
      throw new Error(`Invalid Option: max_record_size must be a positive integer, got ${JSON.stringify(options.max_record_size)}`)
    }
    // Normalize option `objname`
    if(options.objname === undefined || options.objname === null || options.objname === false){
      options.objname = undefined;
    }else if(Buffer.isBuffer(options.objname)){
      if(options.objname.length === 0){
        throw new Error(`Invalid Option: objname must be a non empty buffer`)
      }
      if(options.encoding === null);else {
        options.objname = options.objname.toString(options.encoding);
      }
    }else if(typeof options.objname === 'string'){
      if(options.objname.length === 0){
        throw new Error(`Invalid Option: objname must be a non empty string`)
      }
      // Great, nothing to do
    }else {
      throw new Error(`Invalid Option: objname must be a string or a buffer, got ${options.objname}`)
    }
    // Normalize option `on_record`
    if(options.on_record === undefined || options.on_record === null){
      options.on_record = undefined;
    }else if(typeof options.on_record !== 'function'){
      throw new CsvError('CSV_INVALID_OPTION_ON_RECORD', [
        'Invalid option `on_record`:',
        'expect a function,',
        `got ${JSON.stringify(options.on_record)}`
      ], options)
    }
    // Normalize option `quote`
    if(options.quote === null || options.quote === false || options.quote === ''){
      options.quote = null;
    }else {
      if(options.quote === undefined || options.quote === true){
        options.quote = Buffer.from('"', options.encoding);
      }else if(typeof options.quote === 'string'){
        options.quote = Buffer.from(options.quote, options.encoding);
      }
      if(!Buffer.isBuffer(options.quote)){
        throw new Error(`Invalid Option: quote must be a buffer or a string, got ${JSON.stringify(options.quote)}`)
      }
    }
    // Normalize option `raw`
    if(options.raw === undefined || options.raw === null || options.raw === false){
      options.raw = false;
    }else if(options.raw !== true){
      throw new Error(`Invalid Option: raw must be true, got ${JSON.stringify(options.raw)}`)
    }
    // Normalize option `record_delimiter`
    if(!options.record_delimiter){
      options.record_delimiter = [];
    }else if(!Array.isArray(options.record_delimiter)){
      options.record_delimiter = [options.record_delimiter];
    }
    options.record_delimiter = options.record_delimiter.map( function(rd){
      if(typeof rd === 'string'){
        rd = Buffer.from(rd, options.encoding);
      }
      return rd
    });
    // Normalize option `relax`
    if(typeof options.relax === 'boolean');else if(options.relax === undefined || options.relax === null){
      options.relax = false;
    }else {
      throw new Error(`Invalid Option: relax must be a boolean, got ${JSON.stringify(options.relax)}`)
    }
    // Normalize option `relax_column_count`
    if(typeof options.relax_column_count === 'boolean');else if(options.relax_column_count === undefined || options.relax_column_count === null){
      options.relax_column_count = false;
    }else {
      throw new Error(`Invalid Option: relax_column_count must be a boolean, got ${JSON.stringify(options.relax_column_count)}`)
    }
    if(typeof options.relax_column_count_less === 'boolean');else if(options.relax_column_count_less === undefined || options.relax_column_count_less === null){
      options.relax_column_count_less = false;
    }else {
      throw new Error(`Invalid Option: relax_column_count_less must be a boolean, got ${JSON.stringify(options.relax_column_count_less)}`)
    }
    if(typeof options.relax_column_count_more === 'boolean');else if(options.relax_column_count_more === undefined || options.relax_column_count_more === null){
      options.relax_column_count_more = false;
    }else {
      throw new Error(`Invalid Option: relax_column_count_more must be a boolean, got ${JSON.stringify(options.relax_column_count_more)}`)
    }
    // Normalize option `skip_empty_lines`
    if(typeof options.skip_empty_lines === 'boolean');else if(options.skip_empty_lines === undefined || options.skip_empty_lines === null){
      options.skip_empty_lines = false;
    }else {
      throw new Error(`Invalid Option: skip_empty_lines must be a boolean, got ${JSON.stringify(options.skip_empty_lines)}`)
    }
    // Normalize option `skip_lines_with_empty_values`
    if(typeof options.skip_lines_with_empty_values === 'boolean');else if(options.skip_lines_with_empty_values === undefined || options.skip_lines_with_empty_values === null){
      options.skip_lines_with_empty_values = false;
    }else {
      throw new Error(`Invalid Option: skip_lines_with_empty_values must be a boolean, got ${JSON.stringify(options.skip_lines_with_empty_values)}`)
    }
    // Normalize option `skip_lines_with_error`
    if(typeof options.skip_lines_with_error === 'boolean');else if(options.skip_lines_with_error === undefined || options.skip_lines_with_error === null){
      options.skip_lines_with_error = false;
    }else {
      throw new Error(`Invalid Option: skip_lines_with_error must be a boolean, got ${JSON.stringify(options.skip_lines_with_error)}`)
    }
    // Normalize option `rtrim`
    if(options.rtrim === undefined || options.rtrim === null || options.rtrim === false){
      options.rtrim = false;
    }else if(options.rtrim !== true){
      throw new Error(`Invalid Option: rtrim must be a boolean, got ${JSON.stringify(options.rtrim)}`)
    }
    // Normalize option `ltrim`
    if(options.ltrim === undefined || options.ltrim === null || options.ltrim === false){
      options.ltrim = false;
    }else if(options.ltrim !== true){
      throw new Error(`Invalid Option: ltrim must be a boolean, got ${JSON.stringify(options.ltrim)}`)
    }
    // Normalize option `trim`
    if(options.trim === undefined || options.trim === null || options.trim === false){
      options.trim = false;
    }else if(options.trim !== true){
      throw new Error(`Invalid Option: trim must be a boolean, got ${JSON.stringify(options.trim)}`)
    }
    // Normalize options `trim`, `ltrim` and `rtrim`
    if(options.trim === true && opts.ltrim !== false){
      options.ltrim = true;
    }else if(options.ltrim !== true){
      options.ltrim = false;
    }
    if(options.trim === true && opts.rtrim !== false){
      options.rtrim = true;
    }else if(options.rtrim !== true){
      options.rtrim = false;
    }
    // Normalize option `to`
    if(options.to === undefined || options.to === null){
      options.to = -1;
    }else {
      if(typeof options.to === 'string' && /\d+/.test(options.to)){
        options.to = parseInt(options.to);
      }
      if(Number.isInteger(options.to)){
        if(options.to <= 0){
          throw new Error(`Invalid Option: to must be a positive integer greater than 0, got ${JSON.stringify(opts.to)}`)
        }
      }else {
        throw new Error(`Invalid Option: to must be an integer, got ${JSON.stringify(opts.to)}`)
      }
    }
    // Normalize option `to_line`
    if(options.to_line === undefined || options.to_line === null){
      options.to_line = -1;
    }else {
      if(typeof options.to_line === 'string' && /\d+/.test(options.to_line)){
        options.to_line = parseInt(options.to_line);
      }
      if(Number.isInteger(options.to_line)){
        if(options.to_line <= 0){
          throw new Error(`Invalid Option: to_line must be a positive integer greater than 0, got ${JSON.stringify(opts.to_line)}`)
        }
      }else {
        throw new Error(`Invalid Option: to_line must be an integer, got ${JSON.stringify(opts.to_line)}`)
      }
    }
    this.info = {
      bytes: 0,
      comment_lines: 0,
      empty_lines: 0,
      invalid_field_length: 0,
      lines: 1,
      records: 0
    };
    this.options = options;
    this.state = {
      bomSkipped: false,
      bufBytesStart: 0,
      castField: fnCastField,
      commenting: false,
      // Current error encountered by a record
      error: undefined,
      enabled: options.from_line === 1,
      escaping: false,
      // escapeIsQuote: options.escape === options.quote,
      escapeIsQuote: Buffer.isBuffer(options.escape) && Buffer.isBuffer(options.quote) && Buffer.compare(options.escape, options.quote) === 0,
      // columns can be `false`, `true`, `Array`
      expectedRecordLength: Array.isArray(options.columns) ? options.columns.length : undefined,
      field: new ResizeableBuffer_1(20),
      firstLineToHeaders: fnFirstLineToHeaders,
      needMoreDataSize: Math.max(
        // Skip if the remaining buffer smaller than comment
        options.comment !== null ? options.comment.length : 0,
        // Skip if the remaining buffer can be delimiter
        ...options.delimiter.map( (delimiter) => delimiter.length),
        // Skip if the remaining buffer can be escape sequence
        options.quote !== null ? options.quote.length : 0,
      ),
      previousBuf: undefined,
      quoting: false,
      stop: false,
      rawBuffer: new ResizeableBuffer_1(100),
      record: [],
      recordHasError: false,
      record_length: 0,
      recordDelimiterMaxLength: options.record_delimiter.length === 0 ? 2 : Math.max(...options.record_delimiter.map( (v) => v.length)),
      trimChars: [Buffer.from(' ', options.encoding)[0], Buffer.from('\t', options.encoding)[0]],
      wasQuoting: false,
      wasRowDelimiter: false
    };
  }
  // Implementation of `Transform._transform`
  _transform(buf, encoding, callback){
    if(this.state.stop === true){
      return
    }
    const err = this.__parse(buf, false);
    if(err !== undefined){
      this.state.stop = true;
    }
    callback(err);
  }
  // Implementation of `Transform._flush`
  _flush(callback){
    if(this.state.stop === true){
      return
    }
    const err = this.__parse(undefined, true);
    callback(err);
  }
  // Central parser implementation
  __parse(nextBuf, end){
    const {bom, comment, escape, from_line, ltrim, max_record_size, quote, raw, relax, rtrim, skip_empty_lines, to, to_line} = this.options;
    let {record_delimiter} = this.options;
    const {bomSkipped, previousBuf, rawBuffer, escapeIsQuote} = this.state;
    let buf;
    if(previousBuf === undefined){
      if(nextBuf === undefined){
        // Handle empty string
        this.push(null);
        return
      }else {
        buf = nextBuf;
      }
    }else if(previousBuf !== undefined && nextBuf === undefined){
      buf = previousBuf;
    }else {
      buf = Buffer.concat([previousBuf, nextBuf]);
    }
    // Handle UTF BOM
    if(bomSkipped === false){
      if(bom === false){
        this.state.bomSkipped = true;
      }else if(buf.length < 3){
        // No enough data
        if(end === false){
          // Wait for more data
          this.state.previousBuf = buf;
          return
        }
      }else {
        for(let encoding in boms){
          if(boms[encoding].compare(buf, 0, boms[encoding].length) === 0){
            // Skip BOM
            let bomLength = boms[encoding].length;
            this.state.bufBytesStart += bomLength;
            buf = buf.slice(bomLength);
            // Renormalize original options with the new encoding
            this.__normalizeOptions({...this.__originalOptions, encoding: encoding});
            break
          }
        }
        this.state.bomSkipped = true;
      }
    }
    const bufLen = buf.length;
    let pos;
    for(pos = 0; pos < bufLen; pos++){
      // Ensure we get enough space to look ahead
      // There should be a way to move this out of the loop
      if(this.__needMoreData(pos, bufLen, end)){
        break
      }
      if(this.state.wasRowDelimiter === true){
        this.info.lines++;
        this.state.wasRowDelimiter = false;
      }
      if(to_line !== -1 && this.info.lines > to_line){
        this.state.stop = true;
        this.push(null);
        return
      }
      // Auto discovery of record_delimiter, unix, mac and windows supported
      if(this.state.quoting === false && record_delimiter.length === 0){
        const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos);
        if(record_delimiterCount){
          record_delimiter = this.options.record_delimiter;
        }
      }
      const chr = buf[pos];
      if(raw === true){
        rawBuffer.append(chr);
      }
      if((chr === cr || chr === nl) && this.state.wasRowDelimiter === false ){
        this.state.wasRowDelimiter = true;
      }
      // Previous char was a valid escape char
      // treat the current char as a regular char
      if(this.state.escaping === true){
        this.state.escaping = false;
      }else {
        // Escape is only active inside quoted fields
        // We are quoting, the char is an escape chr and there is a chr to escape
        // if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){
        if(escape !== null && this.state.quoting === true && this.__isEscape(buf, pos, chr) && pos + escape.length < bufLen){
          if(escapeIsQuote){
            if(this.__isQuote(buf, pos+escape.length)){
              this.state.escaping = true;
              pos += escape.length - 1;
              continue
            }
          }else {
            this.state.escaping = true;
            pos += escape.length - 1;
            continue
          }
        }
        // Not currently escaping and chr is a quote
        // TODO: need to compare bytes instead of single char
        if(this.state.commenting === false && this.__isQuote(buf, pos)){
          if(this.state.quoting === true){
            const nextChr = buf[pos+quote.length];
            const isNextChrTrimable = rtrim && this.__isCharTrimable(nextChr);
            const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr);
            const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr);
            const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length);
            // Escape a quote
            // Treat next char as a regular character
            if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){
              pos += escape.length - 1;
            }else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){
              this.state.quoting = false;
              this.state.wasQuoting = true;
              pos += quote.length - 1;
              continue
            }else if(relax === false){
              const err = this.__error(
                new CsvError('CSV_INVALID_CLOSING_QUOTE', [
                  'Invalid Closing Quote:',
                  `got "${String.fromCharCode(nextChr)}"`,
                  `at line ${this.info.lines}`,
                  'instead of delimiter, record delimiter, trimable character',
                  '(if activated) or comment',
                ], this.options, this.__infoField())
              );
              if(err !== undefined) return err
            }else {
              this.state.quoting = false;
              this.state.wasQuoting = true;
              this.state.field.prepend(quote);
              pos += quote.length - 1;
            }
          }else {
            if(this.state.field.length !== 0){
              // In relax mode, treat opening quote preceded by chrs as regular
              if( relax === false ){
                const err = this.__error(
                  new CsvError('INVALID_OPENING_QUOTE', [
                    'Invalid Opening Quote:',
                    `a quote is found inside a field at line ${this.info.lines}`,
                  ], this.options, this.__infoField(), {
                    field: this.state.field,
                  })
                );
                if(err !== undefined) return err
              }
            }else {
              this.state.quoting = true;
              pos += quote.length - 1;
              continue
            }
          }
        }
        if(this.state.quoting === false){
          let recordDelimiterLength = this.__isRecordDelimiter(chr, buf, pos);
          if(recordDelimiterLength !== 0){
            // Do not emit comments which take a full line
            const skipCommentLine = this.state.commenting && (this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0);
            if(skipCommentLine){
              this.info.comment_lines++;
              // Skip full comment line
            }else {
              // Activate records emition if above from_line
              if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){
                this.state.enabled = true;
                this.__resetField();
                this.__resetRecord();
                pos += recordDelimiterLength - 1;
                continue
              }
              // Skip if line is empty and skip_empty_lines activated
              if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){
                this.info.empty_lines++;
                pos += recordDelimiterLength - 1;
                continue
              }
              this.info.bytes = this.state.bufBytesStart + pos;
              const errField = this.__onField();
              if(errField !== undefined) return errField
              this.info.bytes = this.state.bufBytesStart + pos + recordDelimiterLength;
              const errRecord = this.__onRecord();
              if(errRecord !== undefined) return errRecord
              if(to !== -1 && this.info.records >= to){
                this.state.stop = true;
                this.push(null);
                return
              }
            }
            this.state.commenting = false;
            pos += recordDelimiterLength - 1;
            continue
          }
          if(this.state.commenting){
            continue
          }
          const commentCount = comment === null ? 0 : this.__compareBytes(comment, buf, pos, chr);
          if(commentCount !== 0){
            this.state.commenting = true;
            continue
          }
          let delimiterLength = this.__isDelimiter(buf, pos, chr);
          if(delimiterLength !== 0){
            this.info.bytes = this.state.bufBytesStart + pos;
            const errField = this.__onField();
            if(errField !== undefined) return errField
            pos += delimiterLength - 1;
            continue
          }
        }
      }
      if(this.state.commenting === false){
        if(max_record_size !== 0 && this.state.record_length + this.state.field.length > max_record_size){
          const err = this.__error(
            new CsvError('CSV_MAX_RECORD_SIZE', [
              'Max Record Size:',
              'record exceed the maximum number of tolerated bytes',
              `of ${max_record_size}`,
              `at line ${this.info.lines}`,
            ], this.options, this.__infoField())
          );
          if(err !== undefined) return err
        }
      }
      const lappend = ltrim === false || this.state.quoting === true || this.state.field.length !== 0 || !this.__isCharTrimable(chr);
      // rtrim in non quoting is handle in __onField
      const rappend = rtrim === false || this.state.wasQuoting === false;
      if( lappend === true && rappend === true ){
        this.state.field.append(chr);
      }else if(rtrim === true && !this.__isCharTrimable(chr)){
        const err = this.__error(
          new CsvError('CSV_NON_TRIMABLE_CHAR_AFTER_CLOSING_QUOTE', [
            'Invalid Closing Quote:',
            'found non trimable byte after quote',
            `at line ${this.info.lines}`,
          ], this.options, this.__infoField())
        );
        if(err !== undefined) return err
      }
    }
    if(end === true){
      // Ensure we are not ending in a quoting state
      if(this.state.quoting === true){
        const err = this.__error(
          new CsvError('CSV_QUOTE_NOT_CLOSED', [
            'Quote Not Closed:',
            `the parsing is finished with an opening quote at line ${this.info.lines}`,
          ], this.options, this.__infoField())
        );
        if(err !== undefined) return err
      }else {
        // Skip last line if it has no characters
        if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){
          this.info.bytes = this.state.bufBytesStart + pos;
          const errField = this.__onField();
          if(errField !== undefined) return errField
          const errRecord = this.__onRecord();
          if(errRecord !== undefined) return errRecord
        }else if(this.state.wasRowDelimiter === true){
          this.info.empty_lines++;
        }else if(this.state.commenting === true){
          this.info.comment_lines++;
        }
      }
    }else {
      this.state.bufBytesStart += pos;
      this.state.previousBuf = buf.slice(pos);
    }
    if(this.state.wasRowDelimiter === true){
      this.info.lines++;
      this.state.wasRowDelimiter = false;
    }
  }
  __onRecord(){
    const {columns, columns_duplicates_to_array, encoding, info, from, relax_column_count, relax_column_count_less, relax_column_count_more, raw, skip_lines_with_empty_values} = this.options;
    const {enabled, record} = this.state;
    if(enabled === false){
      return this.__resetRecord()
    }
    // Convert the first line into column names
    const recordLength = record.length;
    if(columns === true){
      if(skip_lines_with_empty_values === true && isRecordEmpty(record)){
        this.__resetRecord();
        return
      }
      return this.__firstLineToColumns(record)
    }
    if(columns === false && this.info.records === 0){
      this.state.expectedRecordLength = recordLength;
    }
    if(recordLength !== this.state.expectedRecordLength){
      const err = columns === false ?
        // Todo: rename CSV_INCONSISTENT_RECORD_LENGTH to
        // CSV_RECORD_INCONSISTENT_FIELDS_LENGTH
        new CsvError('CSV_INCONSISTENT_RECORD_LENGTH', [
          'Invalid Record Length:',
          `expect ${this.state.expectedRecordLength},`,
          `got ${recordLength} on line ${this.info.lines}`,
        ], this.options, this.__infoField(), {
          record: record,
        })
      :
        // Todo: rename CSV_RECORD_DONT_MATCH_COLUMNS_LENGTH to
        // CSV_RECORD_INCONSISTENT_COLUMNS
        new CsvError('CSV_RECORD_DONT_MATCH_COLUMNS_LENGTH', [
          'Invalid Record Length:',
          `columns length is ${columns.length},`, // rename columns
          `got ${recordLength} on line ${this.info.lines}`,
        ], this.options, this.__infoField(), {
          record: record,
        });
      if(relax_column_count === true ||
        (relax_column_count_less === true && recordLength < this.state.expectedRecordLength) ||
        (relax_column_count_more === true && recordLength > this.state.expectedRecordLength) ){
        this.info.invalid_field_length++;
        this.state.error = err;
      // Error is undefined with skip_lines_with_error
      }else {
        const finalErr = this.__error(err);
        if(finalErr) return finalErr
      }
    }
    if(skip_lines_with_empty_values === true && isRecordEmpty(record)){
      this.__resetRecord();
      return
    }
    if(this.state.recordHasError === true){
      this.__resetRecord();
      this.state.recordHasError = false;
      return
    }
    this.info.records++;
    if(from === 1 || this.info.records >= from){
      // With columns, records are object
      if(columns !== false){
        const obj = {};
        // Transform record array to an object
        for(let i = 0, l = record.length; i < l; i++){
          if(columns[i] === undefined || columns[i].disabled) continue
          // Turn duplicate columns into an array
          if (columns_duplicates_to_array === true && obj[columns[i].name] !== undefined) {
            if (Array.isArray(obj[columns[i].name])) {
              obj[columns[i].name] = obj[columns[i].name].concat(record[i]);
            } else {
              obj[columns[i].name] = [obj[columns[i].name], record[i]];
            }
          } else {
            obj[columns[i].name] = record[i];
          }
        }
        const {objname} = this.options;
        // Without objname (default)
        if(objname === undefined){
          if(raw === true || info === true){
            const err = this.__push(Object.assign(
              {record: obj},
              (raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {}),
              (info === true ? {info: this.__infoRecord()}: {})
            ));
            if(err){
              return err
            }
          }else {
            const err = this.__push(obj);
            if(err){
              return err
            }
          }
        // With objname (default)
        }else {
          if(raw === true || info === true){
            const err = this.__push(Object.assign(
              {record: [obj[objname], obj]},
              raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {},
              info === true ? {info: this.__infoRecord()}: {}
            ));
            if(err){
              return err
            }
          }else {
            const err = this.__push([obj[objname], obj]);
            if(err){
              return err
            }
          }
        }
      // Without columns, records are array
      }else {
        if(raw === true || info === true){
          const err = this.__push(Object.assign(
            {record: record},
            raw === true ? {raw: this.state.rawBuffer.toString(encoding)}: {},
            info === true ? {info: this.__infoRecord()}: {}
          ));
          if(err){
            return err
          }
        }else {
          const err = this.__push(record);
          if(err){
            return err
          }
        }
      }
    }
    this.__resetRecord();
  }
  __firstLineToColumns(record){
    const {firstLineToHeaders} = this.state;
    try{
      const headers = firstLineToHeaders === undefined ? record : firstLineToHeaders.call(null, record);
      if(!Array.isArray(headers)){
        return this.__error(
          new CsvError('CSV_INVALID_COLUMN_MAPPING', [
            'Invalid Column Mapping:',
            'expect an array from column function,',
            `got ${JSON.stringify(headers)}`
          ], this.options, this.__infoField(), {
            headers: headers,
          })
        )
      }
      const normalizedHeaders = normalizeColumnsArray(headers);
      this.state.expectedRecordLength = normalizedHeaders.length;
      this.options.columns = normalizedHeaders;
      this.__resetRecord();
      return
    }catch(err){
      return err
    }
  }
  __resetRecord(){
    if(this.options.raw === true){
      this.state.rawBuffer.reset();
    }
    this.state.error = undefined;
    this.state.record = [];
    this.state.record_length = 0;
  }
  __onField(){
    const {cast, encoding, rtrim, max_record_size} = this.options;
    const {enabled, wasQuoting} = this.state;
    // Short circuit for the from_line options
    if(enabled === false){
      return this.__resetField()
    }
    let field = this.state.field.toString(encoding);
    if(rtrim === true && wasQuoting === false){
      field = field.trimRight();
    }
    if(cast === true){
      const [err, f] = this.__cast(field);
      if(err !== undefined) return err
      field = f;
    }
    this.state.record.push(field);
    // Increment record length if record size must not exceed a limit
    if(max_record_size !== 0 && typeof field === 'string'){
      this.state.record_length += field.length;
    }
    this.__resetField();
  }
  __resetField(){
    this.state.field.reset();
    this.state.wasQuoting = false;
  }
  __push(record){
    const {on_record} = this.options;
    if(on_record !== undefined){
      const info = this.__infoRecord();
      try{
        record = on_record.call(null, record, info);
      }catch(err){
        return err
      }
      if(record === undefined || record === null){ return }
    }
    this.push(record);
  }
  // Return a tuple with the error and the casted value
  __cast(field){
    const {columns, relax_column_count} = this.options;
    const isColumns = Array.isArray(columns);
    // Dont loose time calling cast
    // because the final record is an object
    // and this field can't be associated to a key present in columns
    if( isColumns === true && relax_column_count && this.options.columns.length <= this.state.record.length ){
      return [undefined, undefined]
    }
    if(this.state.castField !== null){
      try{
        const info = this.__infoField();
        return [undefined, this.state.castField.call(null, field, info)]
      }catch(err){
        return [err]
      }
    }
    if(this.__isFloat(field)){
      return [undefined, parseFloat(field)]
    }else if(this.options.cast_date !== false){
      const info = this.__infoField();
      return [undefined, this.options.cast_date.call(null, field, info)]
    }
    return [undefined, field]
  }
  // Helper to test if a character is a space or a line delimiter
  __isCharTrimable(chr){
    return chr === space || chr === tab || chr === cr || chr === nl || chr === np
  }
  // Keep it in case we implement the `cast_int` option
  // __isInt(value){
  //   // return Number.isInteger(parseInt(value))
  //   // return !isNaN( parseInt( obj ) );
  //   return /^(\-|\+)?[1-9][0-9]*$/.test(value)
  // }
  __isFloat(value){
    return (value - parseFloat( value ) + 1) >= 0 // Borrowed from jquery
  }
  __compareBytes(sourceBuf, targetBuf, targetPos, firstByte){
    if(sourceBuf[0] !== firstByte) return 0
    const sourceLength = sourceBuf.length;
    for(let i = 1; i < sourceLength; i++){
      if(sourceBuf[i] !== targetBuf[targetPos+i]) return 0
    }
    return sourceLength
  }
  __needMoreData(i, bufLen, end){
    if(end) return false
    const {quote} = this.options;
    const {quoting, needMoreDataSize, recordDelimiterMaxLength} = this.state;
    const numOfCharLeft = bufLen - i - 1;
    const requiredLength = Math.max(
      needMoreDataSize,
      // Skip if the remaining buffer smaller than record delimiter
      recordDelimiterMaxLength,
      // Skip if the remaining buffer can be record delimiter following the closing quote
      // 1 is for quote.length
      quoting ? (quote.length + recordDelimiterMaxLength) : 0,
    );
    return numOfCharLeft < requiredLength
  }
  __isDelimiter(buf, pos, chr){
    const {delimiter, ignore_last_delimiters} = this.options;
    if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){
      return 0
    }else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){
      return 0
    }
    loop1: for(let i = 0; i < delimiter.length; i++){
      const del = delimiter[i];
      if(del[0] === chr){
        for(let j = 1; j < del.length; j++){
          if(del[j] !== buf[pos+j]) continue loop1
        }
        return del.length
      }
    }
    return 0
  }
  __isRecordDelimiter(chr, buf, pos){
    const {record_delimiter} = this.options;
    const recordDelimiterLength = record_delimiter.length;
    loop1: for(let i = 0; i < recordDelimiterLength; i++){
      const rd = record_delimiter[i];
      const rdLength = rd.length;
      if(rd[0] !== chr){
        continue
      }
      for(let j = 1; j < rdLength; j++){
        if(rd[j] !== buf[pos+j]){
          continue loop1
        }
      }
      return rd.length
    }
    return 0
  }
  __isEscape(buf, pos, chr){
    const {escape} = this.options;
    if(escape === null) return false
    const l = escape.length;
    if(escape[0] === chr){
      for(let i = 0; i < l; i++){
        if(escape[i] !== buf[pos+i]){
          return false
        }
      }
      return true
    }
    return false
  }
  __isQuote(buf, pos){
    const {quote} = this.options;
    if(quote === null) return false
    const l = quote.length;
    for(let i = 0; i < l; i++){
      if(quote[i] !== buf[pos+i]){
        return false
      }
    }
    return true
  }
  __autoDiscoverRecordDelimiter(buf, pos){
    const {encoding} = this.options;
    const chr = buf[pos];
    if(chr === cr){
      if(buf[pos+1] === nl){
        this.options.record_delimiter.push(Buffer.from('\r\n', encoding));
        this.state.recordDelimiterMaxLength = 2;
        return 2
      }else {
        this.options.record_delimiter.push(Buffer.from('\r', encoding));
        this.state.recordDelimiterMaxLength = 1;
        return 1
      }
    }else if(chr === nl){
      this.options.record_delimiter.push(Buffer.from('\n', encoding));
      this.state.recordDelimiterMaxLength = 1;
      return 1
    }
    return 0
  }
  __error(msg){
    const {skip_lines_with_error} = this.options;
    const err = typeof msg === 'string' ? new Error(msg) : msg;
    if(skip_lines_with_error){
      this.state.recordHasError = true;
      this.emit('skip', err);
      return undefined
    }else {
      return err
    }
  }
  __infoDataSet(){
    return {
      ...this.info,
      columns: this.options.columns
    }
  }
  __infoRecord(){
    const {columns} = this.options;
    return {
      ...this.__infoDataSet(),
      error: this.state.error,
      header: columns === true,
      index: this.state.record.length,
    }
  }
  __infoField(){
    const {columns} = this.options;
    const isColumns = Array.isArray(columns);
    return {
      ...this.__infoRecord(),
      column: isColumns === true ?
        ( columns.length > this.state.record.length ?
          columns[this.state.record.length].name :
          null
        ) :
        this.state.record.length,
      quoting: this.state.wasQuoting,
    }
  }
}

const parse = function(){
  let data, options, callback;
  for(let i in arguments){
    const argument = arguments[i];
    const type = typeof argument;
    if(data === undefined && (typeof argument === 'string' || Buffer.isBuffer(argument))){
      data = argument;
    }else if(options === undefined && isObject(argument)){
      options = argument;
    }else if(callback === undefined && type === 'function'){
      callback = argument;
    }else {
      throw new CsvError('CSV_INVALID_ARGUMENT', [
        'Invalid argument:',
        `got ${JSON.stringify(argument)} at index ${i}`
      ], options || {})
    }
  }
  const parser = new Parser(options);
  if(callback){
    const records = options === undefined || options.objname === undefined ? [] : {};
    parser.on('readable', function(){
      let record;
      while((record = this.read()) !== null){
        if(options === undefined || options.objname === undefined){
          records.push(record);
        }else {
          records[record[0]] = record[1];
        }
      }
    });
    parser.on('error', function(err){
      callback(err, undefined, parser.__infoDataSet());
    });
    parser.on('end', function(){
      callback(undefined, records, parser.__infoDataSet());
    });
  }
  if(data !== undefined){
    // Give a chance for events to be registered later
    if(typeof setImmediate === 'function'){
      setImmediate(function(){
        parser.write(data);
        parser.end();
      });
    }else {
      parser.write(data);
      parser.end();
    }
  }
  return parser
};

class CsvError extends Error {
  constructor(code, message, options, ...contexts) {
    if(Array.isArray(message)) message = message.join(' ');
    super(message);
    if(Error.captureStackTrace !== undefined){
      Error.captureStackTrace(this, CsvError);
    }
    this.code = code;
    for(const context of contexts){
      for(const key in context){
        const value = context[key];
        this[key] = Buffer.isBuffer(value) ? value.toString(options.encoding) : value == null ? value : JSON.parse(JSON.stringify(value));
      }
    }
  }
}

parse.Parser = Parser;

parse.CsvError = CsvError;

var lib = parse;

const underscore = function(str){
  return str.replace(/([A-Z])/g, function(_, match){
    return '_' + match.toLowerCase()
  })
};

const isObject = function(obj){
  return (typeof obj === 'object' && obj !== null && !Array.isArray(obj))
};

const isRecordEmpty = function(record){
  return record.every( (field) => field == null || field.toString && field.toString().trim() === '' )
};

const normalizeColumnsArray = function(columns){
  const normalizedColumns = [];
  for(let i = 0, l = columns.length; i < l; i++){
    const column = columns[i];
    if(column === undefined || column === null || column === false){
      normalizedColumns[i] = { disabled: true };
    }else if(typeof column === 'string'){
      normalizedColumns[i] = { name: column };
    }else if(isObject(column)){
      if(typeof column.name !== 'string'){
        throw new CsvError('CSV_OPTION_COLUMNS_MISSING_NAME', [
          'Option columns missing name:',
          `property "name" is required at position ${i}`,
          'when column is an object literal'
        ])
      }
      normalizedColumns[i] = column;
    }else {
      throw new CsvError('CSV_INVALID_COLUMN_DEFINITION', [
        'Invalid column definition:',
        'expect a string or a literal object,',
        `got ${JSON.stringify(column)} at position ${i}`
      ])
    }
  }
  return normalizedColumns;
};

var sync = function(data, options={}){
  if(typeof data === 'string'){
    data = Buffer.from(data);
  }
  const records = options && options.objname ? {} : [];
  const parser = new lib.Parser(options);
  parser.push = function(record){
    if(record === null){
      return
    }
    if(options.objname === undefined)
      records.push(record);
    else {
      records[record[0]] = record[1];
    }
  };
  const err1 = parser.__parse(data, false);
  if(err1 !== undefined) throw err1
  const err2 = parser.__parse(undefined, true);
  if(err2 !== undefined) throw err2
  return records
};

/* Jison generated parser */
var _parser = (function() {
    var parser = {
        trace: function trace() {},
        yy: {},
        symbols_: {
            "error": 2,
            "expressions": 3,
            "e": 4,
            "EOF": 5,
            "+": 6,
            "-": 7,
            "*": 8,
            "/": 9,
            "%": 10,
            "^": 11,
            "and": 12,
            "or": 13,
            "not": 14,
            "==": 15,
            "!=": 16,
            "~=": 17,
            "<": 18,
            "<=": 19,
            ">": 20,
            ">=": 21,
            "?": 22,
            ":": 23,
            "(": 24,
            ")": 25,
            "array": 26,
            ",": 27,
            "NUMBER": 28,
            "STRING": 29,
            "SYMBOL": 30,
            "of": 31,
            "argsList": 32,
            "in": 33,
            "inSet": 34,
            "$accept": 0,
            "$end": 1
        },
        terminals_: {
            2: "error",
            5: "EOF",
            6: "+",
            7: "-",
            8: "*",
            9: "/",
            10: "%",
            11: "^",
            12: "and",
            13: "or",
            14: "not",
            15: "==",
            16: "!=",
            17: "~=",
            18: "<",
            19: "<=",
            20: ">",
            21: ">=",
            22: "?",
            23: ":",
            24: "(",
            25: ")",
            27: ",",
            28: "NUMBER",
            29: "STRING",
            30: "SYMBOL",
            31: "of",
            33: "in"
        },
        productions_: [0, [3, 2],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 2],
            [4, 3],
            [4, 3],
            [4, 2],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 3],
            [4, 5],
            [4, 3],
            [4, 5],
            [4, 1],
            [4, 1],
            [4, 1],
            [4, 3],
            [4, 3],
            [4, 4],
            [4, 3],
            [4, 4],
            [32, 1],
            [32, 3],
            [34, 1],
            [34, 3],
            [26, 1],
            [26, 3]
        ],
        performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) {

            var $0 = $$.length - 1;
            switch (yystate) {
                case 1:
                    return $$[$0 - 1];
                case 2:
                    this.$ = ["(", $$[$0 - 2], "+", $$[$0], ")"];
                    break;
                case 3:
                    this.$ = ["(", $$[$0 - 2], "-", $$[$0], ")"];
                    break;
                case 4:
                    this.$ = ["(", $$[$0 - 2], "*", $$[$0], ")"];
                    break;
                case 5:
                    this.$ = ["(", $$[$0 - 2], "/", $$[$0], ")"];
                    break;
                case 6:
                    this.$ = ["(", $$[$0 - 2], "%", $$[$0], ")"];
                    break;
                case 7:
                    this.$ = ["(", "Math.pow(", $$[$0 - 2], ",", $$[$0], ")", ")"];
                    break;
                case 8:
                    this.$ = ["(", "-", $$[$0], ")"];
                    break;
                case 9:
                    this.$ = ["(", "Number(", $$[$0 - 2], "&&", $$[$0], ")", ")"];
                    break;
                case 10:
                    this.$ = ["(", "Number(", $$[$0 - 2], "||", $$[$0], ")", ")"];
                    break;
                case 11:
                    this.$ = ["(", "Number(!", $$[$0], ")", ")"];
                    break;
                case 12:
                    this.$ = ["(", "Number(", $$[$0 - 2], "==", $$[$0], ")", ")"];
                    break;
                case 13:
                    this.$ = ["(", "Number(", $$[$0 - 2], "!=", $$[$0], ")", ")"];
                    break;
                case 14:
                    this.$ = ["(", "Number(RegExp(", $$[$0], ").test(", $$[$0 - 2], "))", ")"];
                    break;
                case 15:
                    this.$ = ["(", "Number(", $$[$0 - 2], "<", $$[$0], ")", ")"];
                    break;
                case 16:
                    this.$ = ["(", "Number(", $$[$0 - 2], "<=", $$[$0], ")", ")"];
                    break;
                case 17:
                    this.$ = ["(", "Number(", $$[$0 - 2], "> ", $$[$0], ")", ")"];
                    break;
                case 18:
                    this.$ = ["(", "Number(", $$[$0 - 2], ">=", $$[$0], ")", ")"];
                    break;
                case 19:
                    this.$ = ["(", $$[$0 - 4], "?", $$[$0 - 2], ":", $$[$0], ")"];
                    break;
                case 20:
                    this.$ = ["(", $$[$0 - 1], ")"];
                    break;
                case 21:
                    this.$ = ["(", "[", $$[$0 - 3], ",", $$[$0 - 1], "]", ")"];
                    break;
                case 22:
                    this.$ = ["(", $$[$0], ")"];
                    break;
                case 23:
                    this.$ = ["(", $$[$0], ")"];
                    break;
                case 24:
                    this.$ = ["(", "prop(", $$[$0], ", data)", ")"];
                    break;
                case 25:
                    this.$ = ["(", "prop(", $$[$0 - 2], ",", $$[$0], ")", ")"];
                    break;
                case 26:
                    this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 2], ") ? fns[", $$[$0 - 2], "]() : std.unknown(", $$[$0 - 2], "))", ")"];
                    break;
                case 27:
                    this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 3], ") ? fns[", $$[$0 - 3], "](", $$[$0 - 1], ") : std.unknown(", $$[$0 - 3], "))", ")"];
                    break;
                case 28:
                    this.$ = ["(", "std.isSubset(", $$[$0 - 2], ", ", $$[$0], ")", ")"];
                    break;
                case 29:
                    this.$ = ["(", "+!std.isSubset(", $$[$0 - 3], ", ", $$[$0], ")", ")"];
                    break;
                case 30:
                    this.$ = [$$[$0]];
                    break;
                case 31:
                    this.$ = [$$[$0 - 2], ",", $$[$0]];
                    break;
                case 32:
                    this.$ = ["o ==", $$[$0]];
                    break;
                case 33:
                    this.$ = [$$[$0 - 2], "|| o ==", $$[$0]];
                    break;
                case 34:
                    this.$ = ["(", $$[$0], ")"];
                    break;
                case 35:
                    this.$ = [$$[$0 - 2], ",", $$[$0]];
                    break;
            }
        },
        table: [{
            3: 1,
            4: 2,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            1: [3]
        }, {
            5: [1, 9],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [1, 17],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [1, 25],
            33: [1, 26]
        }, {
            4: 28,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 29,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 30,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            26: 31,
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            5: [2, 22],
            6: [2, 22],
            7: [2, 22],
            8: [2, 22],
            9: [2, 22],
            10: [2, 22],
            11: [2, 22],
            12: [2, 22],
            13: [2, 22],
            14: [2, 22],
            15: [2, 22],
            16: [2, 22],
            17: [2, 22],
            18: [2, 22],
            19: [2, 22],
            20: [2, 22],
            21: [2, 22],
            22: [2, 22],
            23: [2, 22],
            25: [2, 22],
            27: [2, 22],
            33: [2, 22]
        }, {
            5: [2, 23],
            6: [2, 23],
            7: [2, 23],
            8: [2, 23],
            9: [2, 23],
            10: [2, 23],
            11: [2, 23],
            12: [2, 23],
            13: [2, 23],
            14: [2, 23],
            15: [2, 23],
            16: [2, 23],
            17: [2, 23],
            18: [2, 23],
            19: [2, 23],
            20: [2, 23],
            21: [2, 23],
            22: [2, 23],
            23: [2, 23],
            25: [2, 23],
            27: [2, 23],
            33: [2, 23]
        }, {
            5: [2, 24],
            6: [2, 24],
            7: [2, 24],
            8: [2, 24],
            9: [2, 24],
            10: [2, 24],
            11: [2, 24],
            12: [2, 24],
            13: [2, 24],
            14: [2, 24],
            15: [2, 24],
            16: [2, 24],
            17: [2, 24],
            18: [2, 24],
            19: [2, 24],
            20: [2, 24],
            21: [2, 24],
            22: [2, 24],
            23: [2, 24],
            24: [1, 33],
            25: [2, 24],
            27: [2, 24],
            31: [1, 32],
            33: [2, 24]
        }, {
            1: [2, 1]
        }, {
            4: 34,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 35,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 36,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 37,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 38,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 39,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 40,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 41,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 42,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 43,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 44,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 45,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 46,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 47,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 48,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 49,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 50,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            33: [1, 51]
        }, {
            5: [2, 8],
            6: [2, 8],
            7: [2, 8],
            8: [2, 8],
            9: [2, 8],
            10: [2, 8],
            11: [2, 8],
            12: [2, 8],
            13: [2, 8],
            14: [2, 8],
            15: [2, 8],
            16: [2, 8],
            17: [2, 8],
            18: [2, 8],
            19: [2, 8],
            20: [2, 8],
            21: [2, 8],
            22: [2, 8],
            23: [2, 8],
            25: [2, 8],
            27: [2, 8],
            33: [2, 8]
        }, {
            5: [2, 11],
            6: [2, 11],
            7: [2, 11],
            8: [2, 11],
            9: [2, 11],
            10: [2, 11],
            11: [2, 11],
            12: [2, 11],
            13: [2, 11],
            14: [2, 11],
            15: [2, 11],
            16: [2, 11],
            17: [2, 11],
            18: [2, 11],
            19: [2, 11],
            20: [2, 11],
            21: [2, 11],
            22: [2, 11],
            23: [2, 11],
            25: [2, 11],
            27: [2, 11],
            33: [2, 11]
        }, {
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [1, 17],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [1, 25],
            25: [1, 52],
            27: [2, 34],
            33: [1, 26]
        }, {
            27: [1, 53]
        }, {
            4: 54,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            4: 57,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            25: [1, 55],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8],
            32: 56
        }, {
            5: [2, 2],
            6: [2, 2],
            7: [2, 2],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 2],
            13: [2, 2],
            14: [1, 27],
            15: [2, 2],
            16: [2, 2],
            17: [2, 2],
            18: [2, 2],
            19: [2, 2],
            20: [2, 2],
            21: [2, 2],
            22: [2, 2],
            23: [2, 2],
            25: [2, 2],
            27: [2, 2],
            33: [2, 2]
        }, {
            5: [2, 3],
            6: [2, 3],
            7: [2, 3],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 3],
            13: [2, 3],
            14: [1, 27],
            15: [2, 3],
            16: [2, 3],
            17: [2, 3],
            18: [2, 3],
            19: [2, 3],
            20: [2, 3],
            21: [2, 3],
            22: [2, 3],
            23: [2, 3],
            25: [2, 3],
            27: [2, 3],
            33: [2, 3]
        }, {
            5: [2, 4],
            6: [2, 4],
            7: [2, 4],
            8: [2, 4],
            9: [2, 4],
            10: [2, 4],
            11: [1, 15],
            12: [2, 4],
            13: [2, 4],
            14: [1, 27],
            15: [2, 4],
            16: [2, 4],
            17: [2, 4],
            18: [2, 4],
            19: [2, 4],
            20: [2, 4],
            21: [2, 4],
            22: [2, 4],
            23: [2, 4],
            25: [2, 4],
            27: [2, 4],
            33: [2, 4]
        }, {
            5: [2, 5],
            6: [2, 5],
            7: [2, 5],
            8: [2, 5],
            9: [2, 5],
            10: [2, 5],
            11: [1, 15],
            12: [2, 5],
            13: [2, 5],
            14: [1, 27],
            15: [2, 5],
            16: [2, 5],
            17: [2, 5],
            18: [2, 5],
            19: [2, 5],
            20: [2, 5],
            21: [2, 5],
            22: [2, 5],
            23: [2, 5],
            25: [2, 5],
            27: [2, 5],
            33: [2, 5]
        }, {
            5: [2, 6],
            6: [2, 6],
            7: [2, 6],
            8: [2, 6],
            9: [2, 6],
            10: [2, 6],
            11: [1, 15],
            12: [2, 6],
            13: [2, 6],
            14: [1, 27],
            15: [2, 6],
            16: [2, 6],
            17: [2, 6],
            18: [2, 6],
            19: [2, 6],
            20: [2, 6],
            21: [2, 6],
            22: [2, 6],
            23: [2, 6],
            25: [2, 6],
            27: [2, 6],
            33: [2, 6]
        }, {
            5: [2, 7],
            6: [2, 7],
            7: [2, 7],
            8: [2, 7],
            9: [2, 7],
            10: [2, 7],
            11: [2, 7],
            12: [2, 7],
            13: [2, 7],
            14: [1, 27],
            15: [2, 7],
            16: [2, 7],
            17: [2, 7],
            18: [2, 7],
            19: [2, 7],
            20: [2, 7],
            21: [2, 7],
            22: [2, 7],
            23: [2, 7],
            25: [2, 7],
            27: [2, 7],
            33: [2, 7]
        }, {
            5: [2, 9],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 9],
            13: [2, 9],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [2, 9],
            23: [2, 9],
            25: [2, 9],
            27: [2, 9],
            33: [1, 26]
        }, {
            5: [2, 10],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [2, 10],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [2, 10],
            23: [2, 10],
            25: [2, 10],
            27: [2, 10],
            33: [1, 26]
        }, {
            5: [2, 12],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 12],
            13: [2, 12],
            14: [1, 27],
            15: [2, 12],
            16: [2, 12],
            17: [2, 12],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [2, 12],
            23: [2, 12],
            25: [2, 12],
            27: [2, 12],
            33: [2, 12]
        }, {
            5: [2, 13],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 13],
            13: [2, 13],
            14: [1, 27],
            15: [2, 13],
            16: [2, 13],
            17: [2, 13],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [2, 13],
            23: [2, 13],
            25: [2, 13],
            27: [2, 13],
            33: [2, 13]
        }, {
            5: [2, 14],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 14],
            13: [2, 14],
            14: [1, 27],
            15: [2, 14],
            16: [2, 14],
            17: [2, 14],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [2, 14],
            23: [2, 14],
            25: [2, 14],
            27: [2, 14],
            33: [2, 14]
        }, {
            5: [2, 15],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 15],
            13: [2, 15],
            14: [1, 27],
            15: [2, 15],
            16: [2, 15],
            17: [2, 15],
            18: [2, 15],
            19: [2, 15],
            20: [2, 15],
            21: [2, 15],
            22: [2, 15],
            23: [2, 15],
            25: [2, 15],
            27: [2, 15],
            33: [2, 15]
        }, {
            5: [2, 16],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 16],
            13: [2, 16],
            14: [1, 27],
            15: [2, 16],
            16: [2, 16],
            17: [2, 16],
            18: [2, 16],
            19: [2, 16],
            20: [2, 16],
            21: [2, 16],
            22: [2, 16],
            23: [2, 16],
            25: [2, 16],
            27: [2, 16],
            33: [2, 16]
        }, {
            5: [2, 17],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 17],
            13: [2, 17],
            14: [1, 27],
            15: [2, 17],
            16: [2, 17],
            17: [2, 17],
            18: [2, 17],
            19: [2, 17],
            20: [2, 17],
            21: [2, 17],
            22: [2, 17],
            23: [2, 17],
            25: [2, 17],
            27: [2, 17],
            33: [2, 17]
        }, {
            5: [2, 18],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 18],
            13: [2, 18],
            14: [1, 27],
            15: [2, 18],
            16: [2, 18],
            17: [2, 18],
            18: [2, 18],
            19: [2, 18],
            20: [2, 18],
            21: [2, 18],
            22: [2, 18],
            23: [2, 18],
            25: [2, 18],
            27: [2, 18],
            33: [2, 18]
        }, {
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [1, 17],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [1, 25],
            23: [1, 58],
            33: [1, 26]
        }, {
            5: [2, 28],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [2, 28],
            13: [2, 28],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [2, 28],
            23: [2, 28],
            25: [2, 28],
            27: [2, 28],
            33: [2, 28]
        }, {
            4: 59,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            5: [2, 20],
            6: [2, 20],
            7: [2, 20],
            8: [2, 20],
            9: [2, 20],
            10: [2, 20],
            11: [2, 20],
            12: [2, 20],
            13: [2, 20],
            14: [2, 20],
            15: [2, 20],
            16: [2, 20],
            17: [2, 20],
            18: [2, 20],
            19: [2, 20],
            20: [2, 20],
            21: [2, 20],
            22: [2, 20],
            23: [2, 20],
            25: [2, 20],
            27: [2, 20],
            33: [2, 20]
        }, {
            4: 60,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            5: [2, 25],
            6: [2, 25],
            7: [2, 25],
            8: [2, 25],
            9: [2, 25],
            10: [2, 25],
            11: [2, 25],
            12: [2, 25],
            13: [2, 25],
            14: [2, 25],
            15: [2, 25],
            16: [2, 25],
            17: [2, 25],
            18: [2, 25],
            19: [2, 25],
            20: [2, 25],
            21: [2, 25],
            22: [2, 25],
            23: [2, 25],
            25: [2, 25],
            27: [2, 25],
            33: [2, 25]
        }, {
            5: [2, 26],
            6: [2, 26],
            7: [2, 26],
            8: [2, 26],
            9: [2, 26],
            10: [2, 26],
            11: [2, 26],
            12: [2, 26],
            13: [2, 26],
            14: [2, 26],
            15: [2, 26],
            16: [2, 26],
            17: [2, 26],
            18: [2, 26],
            19: [2, 26],
            20: [2, 26],
            21: [2, 26],
            22: [2, 26],
            23: [2, 26],
            25: [2, 26],
            27: [2, 26],
            33: [2, 26]
        }, {
            25: [1, 61],
            27: [1, 62]
        }, {
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [1, 17],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [1, 25],
            25: [2, 30],
            27: [2, 30],
            33: [1, 26]
        }, {
            4: 63,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            5: [2, 29],
            6: [2, 29],
            7: [2, 29],
            8: [2, 29],
            9: [2, 29],
            10: [2, 29],
            11: [2, 29],
            12: [2, 29],
            13: [2, 29],
            14: [2, 29],
            15: [2, 29],
            16: [2, 29],
            17: [2, 29],
            18: [2, 29],
            19: [2, 29],
            20: [2, 29],
            21: [2, 29],
            22: [2, 29],
            23: [2, 29],
            25: [2, 29],
            27: [2, 29],
            33: [2, 29]
        }, {
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [1, 17],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [1, 25],
            25: [1, 64],
            27: [2, 35],
            33: [1, 26]
        }, {
            5: [2, 27],
            6: [2, 27],
            7: [2, 27],
            8: [2, 27],
            9: [2, 27],
            10: [2, 27],
            11: [2, 27],
            12: [2, 27],
            13: [2, 27],
            14: [2, 27],
            15: [2, 27],
            16: [2, 27],
            17: [2, 27],
            18: [2, 27],
            19: [2, 27],
            20: [2, 27],
            21: [2, 27],
            22: [2, 27],
            23: [2, 27],
            25: [2, 27],
            27: [2, 27],
            33: [2, 27]
        }, {
            4: 65,
            7: [1, 3],
            14: [1, 4],
            24: [1, 5],
            28: [1, 6],
            29: [1, 7],
            30: [1, 8]
        }, {
            5: [2, 19],
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [1, 17],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [2, 19],
            23: [2, 19],
            25: [2, 19],
            27: [2, 19],
            33: [1, 26]
        }, {
            5: [2, 21],
            6: [2, 21],
            7: [2, 21],
            8: [2, 21],
            9: [2, 21],
            10: [2, 21],
            11: [2, 21],
            12: [2, 21],
            13: [2, 21],
            14: [2, 21],
            15: [2, 21],
            16: [2, 21],
            17: [2, 21],
            18: [2, 21],
            19: [2, 21],
            20: [2, 21],
            21: [2, 21],
            22: [2, 21],
            23: [2, 21],
            25: [2, 21],
            27: [2, 21],
            33: [2, 21]
        }, {
            6: [1, 10],
            7: [1, 11],
            8: [1, 12],
            9: [1, 13],
            10: [1, 14],
            11: [1, 15],
            12: [1, 16],
            13: [1, 17],
            14: [1, 27],
            15: [1, 18],
            16: [1, 19],
            17: [1, 20],
            18: [1, 21],
            19: [1, 22],
            20: [1, 23],
            21: [1, 24],
            22: [1, 25],
            25: [2, 31],
            27: [2, 31],
            33: [1, 26]
        }],
        defaultActions: {
            9: [2, 1]
        },
        parseError: function parseError(str, hash) {
            throw new Error(str);
        },
        parse: function parse(input) {
            var self = this,
                stack = [0],
                vstack = [null], // semantic value stack
                lstack = [], // location stack
                table = this.table,
                yytext = '',
                yylineno = 0,
                yyleng = 0,
                recovering = 0,
                TERROR = 2,
                EOF = 1;

            //this.reductionCount = this.shiftCount = 0;

            this.lexer.setInput(input);
            this.lexer.yy = this.yy;
            this.yy.lexer = this.lexer;
            this.yy.parser = this;
            if (typeof this.lexer.yylloc == 'undefined')
                this.lexer.yylloc = {};
            var yyloc = this.lexer.yylloc;
            lstack.push(yyloc);

            var ranges = this.lexer.options && this.lexer.options.ranges;

            if (typeof this.yy.parseError === 'function')
                this.parseError = this.yy.parseError;

            function popStack(n) {
                stack.length = stack.length - 2 * n;
                vstack.length = vstack.length - n;
                lstack.length = lstack.length - n;
            }

            function lex() {
                var token;
                token = self.lexer.lex() || 1; // $end = 1
                // if token isn't its numeric value, convert
                if (typeof token !== 'number') {
                    token = self.symbols_[token] || token;
                }
                return token;
            }

            var symbol, preErrorSymbol, state, action, r, yyval = {},
                p, len, newState, expected;
            while (true) {
                // retreive state number from top of stack
                state = stack[stack.length - 1];

                // use default actions if available
                if (this.defaultActions[state]) {
                    action = this.defaultActions[state];
                } else {
                    if (symbol === null || typeof symbol == 'undefined') {
                        symbol = lex();
                    }
                    // read action for current state and first input
                    action = table[state] && table[state][symbol];
                }

                // handle parse error
                if (typeof action === 'undefined' || !action.length || !action[0]) {

                        var errStr = '';
                        if (!recovering) {
                            // Report error
                            expected = [];
                            for (p in table[state])
                                if (this.terminals_[p] && p > 2) {
                                    expected.push("'" + this.terminals_[p] + "'");
                                }
                            if (this.lexer.showPosition) {
                                errStr = 'Parse error on line ' + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(', ') + ", got '" + (this.terminals_[symbol] || symbol) + "'";
                            } else {
                                errStr = 'Parse error on line ' + (yylineno + 1) + ": Unexpected " +
                                    (symbol == 1 /*EOF*/ ? "end of input" :
                                        ("'" + (this.terminals_[symbol] || symbol) + "'"));
                            }
                            this.parseError(errStr, {
                                text: this.lexer.match,
                                token: this.terminals_[symbol] || symbol,
                                line: this.lexer.yylineno,
                                loc: yyloc,
                                expected: expected
                            });
                        }

                        // just recovered from another error
                        if (recovering == 3) {
                            if (symbol == EOF) {
                                throw new Error(errStr || 'Parsing halted.');
                            }

                            // discard current lookahead and grab another
                            yyleng = this.lexer.yyleng;
                            yytext = this.lexer.yytext;
                            yylineno = this.lexer.yylineno;
                            yyloc = this.lexer.yylloc;
                            symbol = lex();
                        }

                        // try to recover from error
                        while (1) {
                            // check for error recovery rule in this state
                            if ((TERROR.toString()) in table[state]) {
                                break;
                            }
                            if (state === 0) {
                                throw new Error(errStr || 'Parsing halted.');
                            }
                            popStack(1);
                            state = stack[stack.length - 1];
                        }

                        preErrorSymbol = symbol == 2 ? null : symbol; // save the lookahead token
                        symbol = TERROR; // insert generic error symbol as new lookahead
                        state = stack[stack.length - 1];
                        action = table[state] && table[state][TERROR];
                        recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
                    }

                // this shouldn't happen, unless resolve defaults are off
                if (action[0] instanceof Array && action.length > 1) {
                    throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
                }

                switch (action[0]) {

                    case 1: // shift
                        //this.shiftCount++;

                        stack.push(symbol);
                        vstack.push(this.lexer.yytext);
                        lstack.push(this.lexer.yylloc);
                        stack.push(action[1]); // push state
                        symbol = null;
                        if (!preErrorSymbol) { // normal execution/no error
                            yyleng = this.lexer.yyleng;
                            yytext = this.lexer.yytext;
                            yylineno = this.lexer.yylineno;
                            yyloc = this.lexer.yylloc;
                            if (recovering > 0)
                                recovering--;
                        } else { // error just occurred, resume old lookahead f/ before error
                            symbol = preErrorSymbol;
                            preErrorSymbol = null;
                        }
                        break;

                    case 2: // reduce
                        //this.reductionCount++;

                        len = this.productions_[action[1]][1];

                        // perform semantic action
                        yyval.$ = vstack[vstack.length - len]; // default to $$ = $1
                        // default location, uses first token for firsts, last for lasts
                        yyval._$ = {
                            first_line: lstack[lstack.length - (len || 1)].first_line,
                            last_line: lstack[lstack.length - 1].last_line,
                            first_column: lstack[lstack.length - (len || 1)].first_column,
                            last_column: lstack[lstack.length - 1].last_column
                        };
                        if (ranges) {
                            yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
                        }
                        r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);

                        if (typeof r !== 'undefined') {
                            return r;
                        }

                        // pop off stack
                        if (len) {
                            stack = stack.slice(0, -1 * len * 2);
                            vstack = vstack.slice(0, -1 * len);
                            lstack = lstack.slice(0, -1 * len);
                        }

                        stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
                        vstack.push(yyval.$);
                        lstack.push(yyval._$);
                        // goto new state = table[STATE][NONTERMINAL]
                        newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
                        stack.push(newState);
                        break;

                    case 3: // accept
                        return true;
                }

            }

            return true;
        }
    };
    var lexer = (function() {
        var lexer = ({
            EOF: 1,
            parseError: function parseError(str, hash) {
                if (this.yy.parser) {
                    this.yy.parser.parseError(str, hash);
                } else {
                    throw new Error(str);
                }
            },
            setInput: function(input) {
                this._input = input;
                this._more = this._less = this.done = false;
                this.yylineno = this.yyleng = 0;
                this.yytext = this.matched = this.match = '';
                this.conditionStack = ['INITIAL'];
                this.yylloc = {
                    first_line: 1,
                    first_column: 0,
                    last_line: 1,
                    last_column: 0
                };
                if (this.options.ranges) this.yylloc.range = [0, 0];
                this.offset = 0;
                return this;
            },
            input: function() {
                var ch = this._input[0];
                this.yytext += ch;
                this.yyleng++;
                this.offset++;
                this.match += ch;
                this.matched += ch;
                var lines = ch.match(/(?:\r\n?|\n).*/g);
                if (lines) {
                    this.yylineno++;
                    this.yylloc.last_line++;
                } else {
                    this.yylloc.last_column++;
                }
                if (this.options.ranges) this.yylloc.range[1]++;

                this._input = this._input.slice(1);
                return ch;
            },
            unput: function(ch) {
                var len = ch.length;
                var lines = ch.split(/(?:\r\n?|\n)/g);

                this._input = ch + this._input;
                this.yytext = this.yytext.substr(0, this.yytext.length - len - 1);
                //this.yyleng -= len;
                this.offset -= len;
                var oldLines = this.match.split(/(?:\r\n?|\n)/g);
                this.match = this.match.substr(0, this.match.length - 1);
                this.matched = this.matched.substr(0, this.matched.length - 1);

                if (lines.length - 1) this.yylineno -= lines.length - 1;
                var r = this.yylloc.range;

                this.yylloc = {
                    first_line: this.yylloc.first_line,
                    last_line: this.yylineno + 1,
                    first_column: this.yylloc.first_column,
                    last_column: lines ?
                        (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len
                };

                if (this.options.ranges) {
                    this.yylloc.range = [r[0], r[0] + this.yyleng - len];
                }
                return this;
            },
            more: function() {
                this._more = true;
                return this;
            },
            less: function(n) {
                this.unput(this.match.slice(n));
            },
            pastInput: function() {
                var past = this.matched.substr(0, this.matched.length - this.match.length);
                return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, "");
            },
            upcomingInput: function() {
                var next = this.match;
                if (next.length < 20) {
                    next += this._input.substr(0, 20 - next.length);
                }
                return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
            },
            showPosition: function() {
                var pre = this.pastInput();
                var c = new Array(pre.length + 1).join("-");
                return pre + this.upcomingInput() + "\n" + c + "^";
            },
            next: function() {
                if (this.done) {
                    return this.EOF;
                }
                if (!this._input) this.done = true;

                var token,
                    match,
                    tempMatch,
                    index,
                    lines;
                if (!this._more) {
                    this.yytext = '';
                    this.match = '';
                }
                var rules = this._currentRules();
                for (var i = 0; i < rules.length; i++) {
                    tempMatch = this._input.match(this.rules[rules[i]]);
                    if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
                        match = tempMatch;
                        index = i;
                        if (!this.options.flex) break;
                    }
                }
                if (match) {
                    lines = match[0].match(/(?:\r\n?|\n).*/g);
                    if (lines) this.yylineno += lines.length;
                    this.yylloc = {
                        first_line: this.yylloc.last_line,
                        last_line: this.yylineno + 1,
                        first_column: this.yylloc.last_column,
                        last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length
                    };
                    this.yytext += match[0];
                    this.match += match[0];
                    this.matches = match;
                    this.yyleng = this.yytext.length;
                    if (this.options.ranges) {
                        this.yylloc.range = [this.offset, this.offset += this.yyleng];
                    }
                    this._more = false;
                    this._input = this._input.slice(match[0].length);
                    this.matched += match[0];
                    token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]);
                    if (this.done && this._input) this.done = false;
                    if (token) return token;
                    else return;
                }
                if (this._input === "") {
                    return this.EOF;
                } else {
                    return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
                        text: "",
                        token: null,
                        line: this.yylineno
                    });
                }
            },
            lex: function lex() {
                var r = this.next();
                if (typeof r !== 'undefined') {
                    return r;
                } else {
                    return this.lex();
                }
            },
            begin: function begin(condition) {
                this.conditionStack.push(condition);
            },
            popState: function popState() {
                return this.conditionStack.pop();
            },
            _currentRules: function _currentRules() {
                return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
            },
            topState: function() {
                return this.conditionStack[this.conditionStack.length - 2];
            },
            pushState: function begin(condition) {
                this.begin(condition);
            }
        });
        lexer.options = {};
        lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) {
            switch ($avoiding_name_collisions) {
                case 0:
                    return "*";
                case 1:
                    return "/";
                case 2:
                    return "-";
                case 3:
                    return "+";
                case 4:
                    return "^";
                case 5:
                    return "%";
                case 6:
                    return "(";
                case 7:
                    return ")";
                case 8:
                    return ",";
                case 9:
                    return "==";
                case 10:
                    return "!=";
                case 11:
                    return "~=";
                case 12:
                    return ">=";
                case 13:
                    return "<=";
                case 14:
                    return "<";
                case 15:
                    return ">";
                case 16:
                    return "?";
                case 17:
                    return ":";
                case 18:
                    return "and";
                case 19:
                    return "or";
                case 20:
                    return "not";
                case 21:
                    return "in";
                case 22:
                    return "of";
                case 23:
                    break;
                case 24:
                    return "NUMBER";
                case 25:
                    yy_.yytext = JSON.stringify(yy_.yytext);
                    return "SYMBOL";
                case 26:
                    yy_.yytext = yy.buildString("'", yy_.yytext);
                    return "SYMBOL";
                case 27:
                    yy_.yytext = yy.buildString('"', yy_.yytext);
                    return "STRING";
                case 28:
                    return "EOF";
            }
        };
        lexer.rules = [/^(?:\*)/, /^(?:\/)/, /^(?:-)/, /^(?:\+)/, /^(?:\^)/, /^(?:\%)/, /^(?:\()/, /^(?:\))/, /^(?:\,)/, /^(?:==)/, /^(?:\!=)/, /^(?:\~=)/, /^(?:>=)/, /^(?:<=)/, /^(?:<)/, /^(?:>)/, /^(?:\?)/, /^(?:\:)/, /^(?:and[^\w])/, /^(?:or[^\w])/, /^(?:not[^\w])/, /^(?:in[^\w])/, /^(?:of[^\w])/, /^(?:\s+)/, /^(?:[0-9]+(?:\.[0-9]+)?\b)/, /^(?:[a-zA-Z$_][\.a-zA-Z0-9$_]*)/, /^(?:'(?:\\'|\\\\|[^'\\])*')/, /^(?:"(?:\\"|\\\\|[^"\\])*")/, /^(?:$)/];
        lexer.conditions = {
            "INITIAL": {
                "rules": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28],
                "inclusive": true
            }
        };
        return lexer;
    })();
    parser.lexer = lexer;

    function Parser() {
        this.yy = {};
    }
    Parser.prototype = parser;
    parser.Parser = Parser;
    return new Parser;
})();
const parser = _parser;
_parser.Parser;

// the parser is dynamically generated from generateParser.js at compile time

// Shared utility functions
const std =
{

    isfn: function(fns, funcName) {
        return fns.hasOwnProperty(funcName) && typeof fns[funcName] === "function";
    },

    unknown: function(funcName) {
        throw ReferenceError('Unknown function: ' + funcName + '()');
    },

    coerceArray: function(value) {
        if (Array.isArray(value))
            return value;
        else
            return [value];
    },

    coerceBoolean: function(value) {
        if (typeof value === 'boolean')
            return +value;
        else
            return value;
    },

    isSubset: function(a, b) {
        const A = std.coerceArray(a);
        const B = std.coerceArray(b);
        return +A.every( val => B.includes(val) );
    },

    buildString: function(quote, literal)
    {
        quote = String(quote)[0];
        literal = String(literal);
        let built = '';

        if (literal[0] !== quote || literal[literal.length-1] !== quote)
            throw new Error(`Unexpected internal error: String literal doesn't begin/end with the right quotation mark.`);

        for (let i = 1; i < literal.length - 1; i++)
        {
            if (literal[i] === "\\")
            {
                i++;
                if (i >= literal.length - 1) throw new Error(`Unexpected internal error: Unescaped backslash at the end of string literal.`);

                if (literal[i] === "\\") built += '\\';
                else if (literal[i] === quote) built += quote;
                else throw new Error(`Unexpected internal error: Invalid escaped character in string literal: ${literal[i]}`);
            }
            else if (literal[i] === quote)
            {
                throw new Error(`Unexpected internal error: String literal contains unescaped quotation mark.`);
            }
            else
            {
                built += literal[i];
            }
        }

        return JSON.stringify(built);
    }
};

parser.yy = Object.create(std);

/**
 * Filtrex provides compileExpression() to compile user expressions to JavaScript.
 *
 * See https://github.com/joewalnes/filtrex for tutorial, reference and examples.
 * MIT License.
 *
 * Includes Jison by Zachary Carter. See http://jison.org/
 *
 * -Joe Walnes
 */
function compileExpression(expression, options) {

    // Check and coerce arguments

    if (arguments.length > 2) throw new TypeError('Too many arguments.');

    options = typeof options === "object" ? options : {};
    let {extraFunctions, customProp} = options;
    for (let key of Object.getOwnPropertyNames(options))
    {
        if (key !== "extraFunctions" && key !== "customProp") throw new TypeError(`Unknown option: ${key}`);
    }



    // Functions available to the expression

    let functions = {
        abs: Math.abs,
        ceil: Math.ceil,
        floor: Math.floor,
        log: Math.log,
        max: Math.max,
        min: Math.min,
        random: Math.random,
        round: Math.round,
        sqrt: Math.sqrt,
    };

    if (extraFunctions) {
        for (var name in extraFunctions) {
            if (extraFunctions.hasOwnProperty(name)) {
                functions[name] = extraFunctions[name];
            }
        }
    }



    // Compile the expression

    let tree = parser.parse(expression);

    let js = [];
    js.push('return ');
    function toJs(node) {
        if (Array.isArray(node)) {
            node.forEach(toJs);
        } else {
            js.push(node);
        }
    }
    tree.forEach(toJs);
    js.push(';');



    // Metaprogramming functions

    function prop(name, obj) {
        return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined;
    }

    function safeGetter(obj) {
        return function get(name) {
            return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined;
        }
    }

    if (typeof customProp === 'function') {
        prop = (name, obj) => std.coerceBoolean(customProp(name, safeGetter(obj), obj));
    }



    // Patch together and return

    let func = new Function('fns', 'std', 'prop', 'data', js.join(''));

    return function(data) {
        try {
            return func(functions, std, prop, data);
        }
        catch (e)
        {
            return e;
        }
    };
}

function applyRowFilters(filters, maxRows = Infinity, rows, columnVariables) {
    const filteredRows = [];
    const expressions = [];
    for (const expression of filters) {
        expressions.push(compileExpression(expression));
    }
    let rowIndex = 1;
    for (const row of rows) {
        let passesTests = true;
        if (rowIndex > maxRows) {
            break;
        }
        for (const expression of expressions) {
            if (!evaluateExpression(row, expression, columnVariables)) {
                passesTests = false;
                break;
            }
        }
        if (passesTests) {
            filteredRows.push(row);
        }
        rowIndex += 1;
    }
    return filteredRows;
}
function sortRows(sortExpressions, rows, columnVariables) {
    const sortedRows = [...rows];
    const expressions = [];
    for (const expression of sortExpressions) {
        expressions.push(compileExpression(expression.expression));
    }
    for (const expression of sortExpressions.reverse()) {
        const sortExpression = compileExpression(expression.expression);
        sortedRows.sort((a, b) => {
            const aResult = evaluateExpression(a, sortExpression, columnVariables);
            const bResult = evaluateExpression(b, sortExpression, columnVariables);
            if (aResult < bResult) {
                return expression.reversed ? 1 : -1;
            }
            else if (aResult > bResult) {
                return expression.reversed ? -1 : 1;
            }
            else {
                return 0;
            }
        });
    }
    return sortedRows;
}
function evaluateExpression(row, expression, columnVariables) {
    const extendedRow = Object.assign({}, row);
    for (const columnVariable in columnVariables !== null && columnVariables !== void 0 ? columnVariables : {}) {
        extendedRow[columnVariable] = row[columnVariables[columnVariable]];
    }
    return expression(extendedRow);
}
function getCellDisplay(row, expression) {
    if (typeof row[expression] === 'string') {
        return row[expression];
    }
    else {
        return JSON.stringify(row[expression]);
    }
}
function getColumnInfo(column) {
    if (typeof column === 'string') {
        return {
            name: column,
            expression: column
        };
    }
    else {
        return column;
    }
}
function getSortExpression(expression) {
    if (typeof expression === 'string') {
        return {
            expression: expression,
            reversed: false
        };
    }
    return expression;
}
function getArrayForArrayOrObject(value) {
    if (value === null || value === undefined) {
        return [];
    }
    if (Array.isArray(value)) {
        return value;
    }
    return [value];
}

function getFilteredCsvData(csvSpec, csvData) {
    var _a, _b, _c;
    const _d = ((_a = csvSpec.csvOptions) !== null && _a !== void 0 ? _a : {}), { cast = true, cast_date = true, trim = true, columns = true, skip_empty_lines = true } = _d, extraOptions = __rest(_d, ["cast", "cast_date", "trim", "columns", "skip_empty_lines"]);
    const csvOptions = Object.assign({ cast, trim, columns, skip_empty_lines }, extraOptions);
    const parsedCsvData = sync(csvData, csvOptions);
    const columnNames = [];
    const rowColumns = Object.keys(parsedCsvData[0]);
    try {
        for (const column of (_b = csvSpec.columns) !== null && _b !== void 0 ? _b : rowColumns) {
            const columnInfo = getColumnInfo(column);
            // Do not attempt to compile/set the expression value
            // if it already exists in our known row columns
            if (rowColumns.indexOf(columnInfo.name) === -1) {
                const expression = compileExpression(columnInfo.expression);
                for (const row of parsedCsvData) {
                    row[columnInfo.name] = evaluateExpression(row, expression, csvSpec.columnVariables);
                }
            }
            columnNames.push(columnInfo.name);
        }
    }
    catch (e) {
        throw new Error(`Error evaluating column expressions: ${e.message}.`);
    }
    let filteredSortedCsvData = [];
    try {
        filteredSortedCsvData = sortRows(getArrayForArrayOrObject(csvSpec.sortBy).map(getSortExpression), applyRowFilters(getArrayForArrayOrObject(csvSpec.filter), (_c = csvSpec.maxRows) !== null && _c !== void 0 ? _c : Infinity, parsedCsvData, csvSpec.columnVariables), csvSpec.columnVariables);
    }
    catch (e) {
        throw new Error(`Error evaluating filter expressions: ${e.message}.`);
    }
    return {
        columns: columnNames,
        rows: filteredSortedCsvData
    };
}

class TableRenderer extends obsidian.MarkdownRenderChild {
    constructor(columns, rows, container) {
        super(container);
        this.columns = columns;
        this.rows = rows;
        this.container = container;
    }
    onload() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.render();
        });
    }
    render() {
        return __awaiter(this, void 0, void 0, function* () {
            const tableEl = this.container.createEl('table');
            const theadEl = tableEl.createEl('thead');
            const headerEl = theadEl.createEl('tr');
            const tbodyEl = tableEl.createEl('tbody');
            const columnNames = [];
            for (const column of this.columns) {
                const columnInfo = getColumnInfo(column);
                headerEl.createEl('th', { text: columnInfo.name });
                columnNames.push(columnInfo.name);
            }
            for (const row of this.rows) {
                const trEl = tbodyEl.createEl('tr');
                for (const columnName of columnNames) {
                    trEl.createEl('td', { text: getCellDisplay(row, columnName) });
                }
            }
        });
    }
}
function renderErrorPre(container, error) {
    let pre = container.createEl('pre', { cls: ["csv-table", "csv-error"] });
    pre.appendText(error);
    return pre;
}

class CsvTablePlugin extends obsidian.Plugin {
    onload() {
        return __awaiter(this, void 0, void 0, function* () {
            this.registerMarkdownCodeBlockProcessor("csvtable", (csvSpecString, el, ctx) => __awaiter(this, void 0, void 0, function* () {
                try {
                    let tableSpec = {
                        source: "", // Assert that this has a proper value below
                    };
                    try {
                        tableSpec = obsidian.parseYaml(csvSpecString);
                    }
                    catch (e) {
                        throw new Error(`Could not parse CSV table spec: ${e.message}`);
                    }
                    if (!tableSpec.source) {
                        throw new Error("Parameter 'source' is required.");
                    }
                    const file = this.app.vault.getAbstractFileByPath(tableSpec.source);
                    if (!(file instanceof obsidian.TFile)) {
                        throw new Error(`CSV file '${tableSpec.source}' could not be found.`);
                    }
                    const csvData = yield this.app.vault.cachedRead(file);
                    console.log("Cached read success");
                    const filteredCsvData = getFilteredCsvData(tableSpec, csvData);
                    ctx.addChild(new TableRenderer(filteredCsvData.columns, filteredCsvData.rows, el));
                }
                catch (e) {
                    renderErrorPre(el, e.message);
                    return;
                }
            }));
        });
    }
}

module.exports = CsvTablePlugin;


/* nosourcemap */