spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
Switching to npm instead of browser based developement (working!)
author
Ben Vogt <[email protected]>
date
2016-12-27 18:53:29
stats
22 file(s) changed, 44 insertions(+), 26450 deletions(-)
files
README.md
js/mine.js
js/parser.js
js/ruleJS.js
lib/formulajs/formula.js
lib/js-md5/md5.js
lib/jstat/jstat.js
lib/lodash/lodash.js
lib/moment/moment.js
lib/numeral/numeral.js
lib/numericjs/numeric.js
lib/underscore.string/underscore.string.js
mine.html
package.json
rule.html
ts.html
ts/Main.ts
ts/Parser.d.ts
ts/parser.js
lib/parser.js
ts/sheet.js
ts/sheet.ts
ts/Sheet.ts
tsconfig.json
    1diff --git a/README.md b/README.md
    2index 51f909b..5ecc9a2 100644
    3--- a/README.md
    4+++ b/README.md
    5@@ -3,10 +3,3 @@ TypeScript implementation of a spreadsheet.
    6 
    7 ## TODO
    8 Things I should do.
    9-
   10-## THE PLAN FROM NOW ON
   11-Take ruleJS.js and slowly alter it slowly.
   12-Step by step build up to a model that is not DOM-based.
   13-Then introduce types.
   14-Then introduce classes.
   15-
   16diff --git a/js/mine.js b/js/mine.js
   17deleted file mode 100644
   18index da6a654..0000000
   19--- a/js/mine.js
   20+++ /dev/null
   21@@ -1,662 +0,0 @@
   22-var mine = (function () {
   23-  'use strict';
   24-  var instance = this;
   25-
   26-  var parser = {};
   27-
   28-  var FormulaParser = function(handler) {
   29-    var formulaLexer = function () {};
   30-    formulaLexer.prototype = Parser.lexer;
   31-
   32-    var formulaParser = function () {
   33-      this.lexer = new formulaLexer();
   34-      this.yy = {};
   35-    };
   36-
   37-    formulaParser.prototype = Parser;
   38-    var newParser = new formulaParser;
   39-    newParser.setObj = function(obj) {
   40-      newParser.yy.obj = obj;
   41-    };
   42-
   43-    newParser.yy.parseError = function (str, hash) {
   44-      throw {
   45-        name: 'Parser error',
   46-        message: str,
   47-        prop: hash
   48-      }
   49-    };
   50-
   51-    newParser.yy.handler = handler;
   52-
   53-    return newParser;
   54-  };
   55-
   56-  var Exception = {
   57-    errors: [
   58-      {type: 'NULL', output: '#NULL'},
   59-      {type: 'DIV_ZERO', output: '#DIV/0!'},
   60-      {type: 'VALUE', output: '#VALUE!'},
   61-      {type: 'REF', output: '#REF!'},
   62-      {type: 'NAME', output: '#NAME?'},
   63-      {type: 'NUM', output: '#NUM!'},
   64-      {type: 'NOT_AVAILABLE', output: '#N/A!'},
   65-      {type: 'ERROR', output: '#ERROR'}
   66-    ],
   67-    get: function (type) {
   68-      var error = Exception.errors.filter(function (item) {
   69-        return item.type === type || item.output === type;
   70-      })[0];
   71-
   72-      return error ? error.output : null;
   73-    }
   74-  };
   75-
   76-  var Matrix = function () {
   77-
   78-    // var item = {
   79-    //   id: '',
   80-    //   formula: '',
   81-    //   value: '',
   82-    //   error: '',
   83-    //   deps: [],
   84-    //   formulaEdit: false
   85-    // };
   86-
   87-    this.data = [];
   88-
   89-    this.getItem = function (id) {
   90-      return instance.matrix.data.filter(function (item) {
   91-        return item.id === id;
   92-      })[0];
   93-    };
   94-
   95-    this.removeItem = function (id) {
   96-      instance.matrix.data = instance.matrix.data.filter(function (item) {
   97-        return item.id !== id;
   98-      });
   99-    };
  100-
  101-    this.updateItem = function (item, props) {
  102-      if (instance.utils.isString(item)) {
  103-        item = instance.matrix.getItem(item);
  104-      }
  105-
  106-      if (item && props) {
  107-        for (var p in props) {
  108-          if (item[p] && instance.utils.isArray(item[p])) {
  109-            if (instance.utils.isArray(props[p])) {
  110-              props[p].forEach(function (i) {
  111-                if (item[p].indexOf(i) === -1) {
  112-                  item[p].push(i);
  113-                }
  114-              });
  115-            } else {
  116-
  117-              if (item[p].indexOf(props[p]) === -1) {
  118-                item[p].push(props[p]);
  119-              }
  120-            }
  121-          } else {
  122-            item[p] = props[p];
  123-          }
  124-        }
  125-      }
  126-    };
  127-
  128-    this.addItem = function (item) {
  129-      var cellId = item.id,
  130-        coords = instance.utils.cellCoords(cellId);
  131-
  132-      item.row = coords.row;
  133-      item.col = coords.col;
  134-
  135-      var cellExist = instance.matrix.data.filter(function (cell) {
  136-        return cell.id === cellId;
  137-      })[0];
  138-
  139-      if (!cellExist) {
  140-        instance.matrix.data.push(item);
  141-      } else {
  142-        instance.matrix.updateItem(cellExist, item);
  143-      }
  144-
  145-      return instance.matrix.getItem(cellId);
  146-    };
  147-
  148-
  149-    this.updateCellItem = function (id, props) {
  150-      var item = instance.matrix.getItem(id);
  151-
  152-      instance.matrix.updateItem(item, props);
  153-    };
  154-
  155-    this.getDependencies = function (id) {
  156-      var getDependencies = function (id) {
  157-        var filtered = instance.matrix.data.filter(function (cell) {
  158-          if (cell.deps) {
  159-            return cell.deps.indexOf(id) > -1;
  160-          }
  161-        });
  162-
  163-        var deps = [];
  164-        filtered.forEach(function (cell) {
  165-          if (deps.indexOf(cell.id) === -1) {
  166-            deps.push(cell.id);
  167-          }
  168-        });
  169-
  170-        return deps;
  171-      };
  172-
  173-      var allDependencies = [];
  174-
  175-      var getTotalDependencies = function (id) {
  176-        var deps = getDependencies(id);
  177-
  178-        if (deps.length) {
  179-          deps.forEach(function (refId) {
  180-            if (allDependencies.indexOf(refId) === -1) {
  181-              allDependencies.push(refId);
  182-
  183-              var item = instance.matrix.getItem(refId);
  184-              if (item.deps.length) {
  185-                getTotalDependencies(refId);
  186-              }
  187-            }
  188-          });
  189-        }
  190-      };
  191-
  192-      getTotalDependencies(id);
  193-
  194-      return allDependencies;
  195-    };
  196-
  197-    this.getCellDependencies = function (cell) {
  198-      return instance.matrix.getDependencies(cell.id);
  199-    };
  200-
  201-    var recalculateCellDependencies = function (cell) {
  202-      var allDependencies = instance.matrix.getCellDependencies(cell);
  203-
  204-      allDependencies.forEach(function (refId) {
  205-        var currentCell = instance.matrix.getItem(refId);
  206-        if (currentCell && currentCell.formula) {
  207-          calculateCellFormula(currentCell.formula, currentCell.id);
  208-        }
  209-      });
  210-    };
  211-
  212-    var calculateCellFormula = function (formula, id) {
  213-      // to avoid double translate formulas, update item data in parser
  214-      var parsed = parse(formula, id),
  215-        value = parsed.result,
  216-        error = parsed.error;
  217-
  218-      instance.matrix.updateCellItem(id, {value: value, error: error});
  219-
  220-      return parsed;
  221-    };
  222-
  223-    var registerCellInMatrix = function (cell) {
  224-      instance.matrix.addItem(cell);
  225-      calculateCellFormula(cell.formula, cell.id);
  226-    };
  227-
  228-    this.scan = function () {
  229-      var input = [
  230-        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "SUM(A1:D1, H1)"],
  231-        [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "MAX(A2:J2)"],
  232-        [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "MIN(A3:J3)"],
  233-        [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "AVERAGE(A4:J4)"],
  234-        [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "SUMIF(A5:J5,'>5')"]
  235-      ];
  236-      for (var y = 0; y < input.length; y++) {
  237-        for (var x = 0; x < input[0].length; x++) {
  238-          // set the cell here
  239-          var id = utils.XYtoA1(x, y);
  240-          var cell = {
  241-            id: id,
  242-            formula: input[y][x].toString()
  243-          };
  244-          registerCellInMatrix(cell);
  245-          recalculateCellDependencies(cell);
  246-        }
  247-      }
  248-      console.log(this.data);
  249-    };
  250-  };
  251-
  252-  var utils = {
  253-    isArray: function (value) {
  254-      return Object.prototype.toString.call(value) === '[object Array]';
  255-    },
  256-
  257-    isNumber: function (value) {
  258-      return Object.prototype.toString.call(value) === '[object Number]';
  259-    },
  260-
  261-    isString: function (value) {
  262-      return Object.prototype.toString.call(value) === '[object String]';
  263-    },
  264-
  265-    isFunction: function (value) {
  266-      return Object.prototype.toString.call(value) === '[object Function]';
  267-    },
  268-
  269-    isUndefined: function (value) {
  270-      return Object.prototype.toString.call(value) === '[object Undefined]';
  271-    },
  272-
  273-    isNull: function (value) {
  274-      return Object.prototype.toString.call(value) === '[object Null]';
  275-    },
  276-
  277-    isSet: function (value) {
  278-      return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
  279-    },
  280-
  281-    getCellAlphaNum: function (cell) {
  282-      var num = cell.match(/\d+$/),
  283-        alpha = cell.replace(num, '');
  284-
  285-      return {
  286-        alpha: alpha,
  287-        num: parseInt(num[0], 10)
  288-      }
  289-    },
  290-
  291-    toNum: function (chr) {
  292-      chr = instance.utils.clearFormula(chr);
  293-      var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
  294-
  295-      for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
  296-        result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
  297-      }
  298-
  299-      if (result) {
  300-        --result;
  301-      }
  302-
  303-      return result;
  304-    },
  305-
  306-    toChar: function (num) {
  307-      var s = '';
  308-
  309-      while (num >= 0) {
  310-        s = String.fromCharCode(num % 26 + 97) + s;
  311-        num = Math.floor(num / 26) - 1;
  312-      }
  313-
  314-      return s.toUpperCase();
  315-    },
  316-    XYtoA1: function (x, y) {
  317-      function numberToLetters(num) {
  318-        var mod = num % 26,
  319-          pow = num / 26 | 0,
  320-          out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
  321-        return pow ? numberToLetters(pow) + out : out;
  322-      }
  323-      return numberToLetters(x+1) + (y+1).toString();
  324-    },
  325-    cellCoords: function (cell) {
  326-      var num = cell.match(/\d+$/),
  327-        alpha = cell.replace(num, '');
  328-
  329-      return {
  330-        row: parseInt(num[0], 10) - 1,
  331-        col: instance.utils.toNum(alpha)
  332-      };
  333-    },
  334-
  335-    clearFormula: function (formula) {
  336-      return formula.replace(/\$/g, '');
  337-    },
  338-
  339-    translateCellCoords: function (coords) {
  340-      return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
  341-    },
  342-
  343-    iterateCells: function (startCell, endCell, callback) {
  344-      var result = {
  345-        index: [], // list of cell index: A1, A2, A3
  346-        value: []  // list of cell value
  347-      };
  348-
  349-      var cols = {
  350-        start: 0,
  351-        end: 0
  352-      };
  353-
  354-      if (endCell.col >= startCell.col) {
  355-        cols = {
  356-          start: startCell.col,
  357-          end: endCell.col
  358-        };
  359-      } else {
  360-        cols = {
  361-          start: endCell.col,
  362-          end: startCell.col
  363-        };
  364-      }
  365-
  366-      var rows = {
  367-        start: 0,
  368-        end: 0
  369-      };
  370-
  371-      if (endCell.row >= startCell.row) {
  372-        rows = {
  373-          start: startCell.row,
  374-          end: endCell.row
  375-        };
  376-      } else {
  377-        rows = {
  378-          start: endCell.row,
  379-          end: startCell.row
  380-        };
  381-      }
  382-
  383-      for (var column = cols.start; column <= cols.end; column++) {
  384-        for (var row = rows.start; row <= rows.end; row++) {
  385-          var cellIndex = instance.utils.toChar(column) + (row + 1),
  386-            cellValue = instance.helper.cellValue.call(this, cellIndex);
  387-
  388-          result.index.push(cellIndex);
  389-          result.value.push(cellValue);
  390-        }
  391-      }
  392-
  393-      if (instance.utils.isFunction(callback)) {
  394-        return callback.apply(callback, [result]);
  395-      } else {
  396-        return result;
  397-      }
  398-    },
  399-
  400-    sort: function (rev) {
  401-      return function (a, b) {
  402-        return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
  403-      }
  404-    }
  405-  };
  406-
  407-  var helper = {
  408-    SUPPORTED_FORMULAS: [
  409-      'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
  410-      'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
  411-      'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
  412-      'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
  413-      'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
  414-      'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
  415-      'IF', 'INT', 'ISEVEN', 'ISODD',
  416-      'LN', 'LOG', 'LOG10',
  417-      'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
  418-      'NOT',
  419-      'ODD', 'OR',
  420-      'PI', 'POWER',
  421-      'ROUND', 'ROUNDDOWN', 'ROUNDUP',
  422-      'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
  423-      'TAN', 'TANH', 'TRUE', 'TRUNC',
  424-      'XOR'
  425-    ],
  426-
  427-    number: function (num) {
  428-      switch (typeof num) {
  429-        case 'number':
  430-          return num;
  431-        case 'string':
  432-          if (!isNaN(num)) {
  433-            return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
  434-          }
  435-      }
  436-
  437-      return num;
  438-    },
  439-
  440-    string: function (str) {
  441-      return str.substring(1, str.length - 1);
  442-    },
  443-
  444-    numberInverted: function (num) {
  445-      return this.number(num) * (-1);
  446-    },
  447-
  448-    specialMatch: function (type, exp1, exp2) {
  449-      var result;
  450-
  451-      switch (type) {
  452-        case '&':
  453-          result = exp1.toString() + exp2.toString();
  454-          break;
  455-      }
  456-      return result;
  457-    },
  458-
  459-    logicMatch: function (type, exp1, exp2) {
  460-      var result;
  461-
  462-      switch (type) {
  463-        case '=':
  464-          result = (exp1 === exp2);
  465-          break;
  466-
  467-        case '>':
  468-          result = (exp1 > exp2);
  469-          break;
  470-
  471-        case '<':
  472-          result = (exp1 < exp2);
  473-          break;
  474-
  475-        case '>=':
  476-          result = (exp1 >= exp2);
  477-          break;
  478-
  479-        case '<=':
  480-          result = (exp1 === exp2);
  481-          break;
  482-
  483-        case '<>':
  484-          result = (exp1 != exp2);
  485-          break;
  486-
  487-        case 'NOT':
  488-          result = (exp1 != exp2);
  489-          break;
  490-      }
  491-
  492-      return result;
  493-    },
  494-
  495-    mathMatch: function (type, number1, number2) {
  496-      var result;
  497-
  498-      number1 = helper.number(number1);
  499-      number2 = helper.number(number2);
  500-
  501-      if (isNaN(number1) || isNaN(number2)) {
  502-        throw Error('VALUE');
  503-      }
  504-
  505-      switch (type) {
  506-        case '+':
  507-          result = number1 + number2;
  508-          break;
  509-        case '-':
  510-          result = number1 - number2;
  511-          break;
  512-        case '/':
  513-          result = number1 / number2;
  514-          if (result == Infinity) {
  515-            throw Error('DIV_ZERO');
  516-          } else if (isNaN(result)) {
  517-            throw Error('VALUE');
  518-          }
  519-          break;
  520-        case '*':
  521-          result = number1 * number2;
  522-          break;
  523-        case '^':
  524-          result = Math.pow(number1, number2);
  525-          break;
  526-      }
  527-
  528-      return result;
  529-    },
  530-
  531-    callFunction: function (fn, args) {
  532-      fn = fn.toUpperCase();
  533-      args = args || [];
  534-
  535-      if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
  536-        if (instance.formulas[fn]) {
  537-          return instance.formulas[fn].apply(this, args);
  538-        }
  539-      }
  540-
  541-      throw Error('NAME');
  542-    },
  543-
  544-    callVariable: function (args) {
  545-      args = args || [];
  546-      var str = args[0];
  547-
  548-      if (str) {
  549-        str = str.toUpperCase();
  550-        if (instance.formulas[str]) {
  551-          return ((typeof instance.formulas[str] === 'function') ? instance.formulas[str].apply(this, args) : instance.formulas[str]);
  552-        }
  553-      }
  554-
  555-      throw Error('NAME');
  556-    },
  557-
  558-    cellValue: function (cell) {
  559-      var value,
  560-        element = this,
  561-        item = instance.matrix.getItem(cell);
  562-      // get value
  563-      value = item ? item.value : "0"; // TODO: fix this, it's sloppy.
  564-      //update dependencies
  565-      instance.matrix.updateCellItem(element, {deps: [cell]});
  566-      // check references error
  567-      if (item && item.deps) {
  568-        if (item.deps.indexOf(cellId) !== -1) {
  569-          throw Error('REF');
  570-        }
  571-      }
  572-
  573-      // check if any error occurs
  574-      if (item && item.error) {
  575-        throw Error(item.error);
  576-      }
  577-
  578-      // return value if is set
  579-      if (instance.utils.isSet(value)) {
  580-        var result = instance.helper.number(value);
  581-
  582-        return !isNaN(result) ? result : value;
  583-      }
  584-
  585-      // cell is not available
  586-      throw Error('NOT_AVAILABLE');
  587-    },
  588-
  589-    cellRangeValue: function (start, end) {
  590-      var coordsStart = instance.utils.cellCoords(start),
  591-        coordsEnd = instance.utils.cellCoords(end),
  592-        element = this;
  593-
  594-      // iterate cells to get values and indexes
  595-      var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd),
  596-        result = [];
  597-      //update dependencies
  598-      instance.matrix.updateCellItem(element, {deps: cells.index});
  599-
  600-      result.push(cells.value);
  601-      return result;
  602-    },
  603-
  604-    fixedCellValue: function (id) {
  605-      id = id.replace(/\$/g, '');
  606-      return instance.helper.cellValue.call(this, id);
  607-    },
  608-
  609-    fixedCellRangeValue: function (start, end) {
  610-      start = start.replace(/\$/g, '');
  611-      end = end.replace(/\$/g, '');
  612-
  613-      return instance.helper.cellRangeValue.call(this, start, end);
  614-    }
  615-  };
  616-
  617-  var parse = function (formula, element) {
  618-    var result = null,
  619-      error = null;
  620-
  621-    try {
  622-
  623-      parser.setObj(element);
  624-      result = parser.parse(formula);
  625-
  626-      var id;
  627-
  628-      if (element instanceof HTMLElement) {
  629-        id = element.getAttribute('id');
  630-      } else if (element && element.id) {
  631-        id = element.id;
  632-      }
  633-
  634-      var deps = instance.matrix.getDependencies(id);
  635-
  636-      if (deps.indexOf(id) !== -1) {
  637-        result = null;
  638-
  639-        deps.forEach(function (id) {
  640-          instance.matrix.updateItem(id, {value: null, error: Exception.get('REF')});
  641-        });
  642-
  643-        throw Error('REF');
  644-      }
  645-
  646-    } catch (ex) {
  647-
  648-      var message = Exception.get(ex.message);
  649-
  650-      if (message) {
  651-        error = message;
  652-      } else {
  653-        error = Exception.get('ERROR');
  654-      }
  655-    }
  656-
  657-    return {
  658-      error: error,
  659-      result: result
  660-    }
  661-  };
  662-
  663-  var init = function () {
  664-    instance = this;
  665-
  666-    parser = new FormulaParser(instance);
  667-
  668-    instance.formulas = Formula;
  669-    instance.matrix = new Matrix();
  670-
  671-    instance.custom = {};
  672-
  673-    instance.matrix.scan();
  674-  };
  675-
  676-  return {
  677-    init: init,
  678-    utils: utils,
  679-    helper: helper,
  680-    parse: parse
  681-  };
  682-
  683-});
  684diff --git a/js/ruleJS.js b/js/ruleJS.js
  685deleted file mode 100644
  686index c3a6fed..0000000
  687--- a/js/ruleJS.js
  688+++ /dev/null
  689@@ -1,777 +0,0 @@
  690-var ruleJS = (function (root) {
  691-  'use strict';
  692-  var instance = this;
  693-
  694-  var rootElement = document.getElementById(root) || null;
  695-
  696-  var parser = {};
  697-
  698-  var FormulaParser = function(handler) {
  699-    var formulaLexer = function () {};
  700-    formulaLexer.prototype = Parser.lexer;
  701-
  702-    var formulaParser = function () {
  703-      this.lexer = new formulaLexer();
  704-      this.yy = {};
  705-    };
  706-
  707-    formulaParser.prototype = Parser;
  708-    var newParser = new formulaParser;
  709-    newParser.setObj = function(obj) {
  710-      newParser.yy.obj = obj;
  711-    };
  712-
  713-    newParser.yy.parseError = function (str, hash) {
  714-      throw {
  715-        name: 'Parser error',
  716-        message: str,
  717-        prop: hash
  718-      }
  719-    };
  720-
  721-    newParser.yy.handler = handler;
  722-
  723-    return newParser;
  724-  };
  725-
  726-  var Exception = {
  727-    errors: [
  728-      {type: 'NULL', output: '#NULL'},
  729-      {type: 'DIV_ZERO', output: '#DIV/0!'},
  730-      {type: 'VALUE', output: '#VALUE!'},
  731-      {type: 'REF', output: '#REF!'},
  732-      {type: 'NAME', output: '#NAME?'},
  733-      {type: 'NUM', output: '#NUM!'},
  734-      {type: 'NOT_AVAILABLE', output: '#N/A!'},
  735-      {type: 'ERROR', output: '#ERROR'}
  736-    ],
  737-    get: function (type) {
  738-      var error = Exception.errors.filter(function (item) {
  739-        return item.type === type || item.output === type;
  740-      })[0];
  741-
  742-      return error ? error.output : null;
  743-    }
  744-  };
  745-
  746-  var Matrix = function () {
  747-
  748-    // var item = {
  749-    //   id: '',
  750-    //   formula: '',
  751-    //   value: '',
  752-    //   error: '',
  753-    //   deps: [],
  754-    //   formulaEdit: false
  755-    // };
  756-
  757-    this.data = [];
  758-
  759-    var formElements = ['input[type=text]', '[data-formula]'];
  760-
  761-    var listen = function () {
  762-      if (document.activeElement && document.activeElement !== document.body) {
  763-        document.activeElement.blur();
  764-      }
  765-      else if (!document.activeElement) { //IE
  766-        document.body.focus();
  767-      }
  768-    };
  769-
  770-    this.getItem = function (id) {
  771-      return instance.matrix.data.filter(function (item) {
  772-        return item.id === id;
  773-      })[0];
  774-    };
  775-
  776-    this.removeItem = function (id) {
  777-      instance.matrix.data = instance.matrix.data.filter(function (item) {
  778-        return item.id !== id;
  779-      });
  780-    };
  781-
  782-    this.updateItem = function (item, props) {
  783-      if (instance.utils.isString(item)) {
  784-        item = instance.matrix.getItem(item);
  785-      }
  786-
  787-      if (item && props) {
  788-        for (var p in props) {
  789-          if (item[p] && instance.utils.isArray(item[p])) {
  790-            if (instance.utils.isArray(props[p])) {
  791-              props[p].forEach(function (i) {
  792-                if (item[p].indexOf(i) === -1) {
  793-                  item[p].push(i);
  794-                }
  795-              });
  796-            } else {
  797-
  798-              if (item[p].indexOf(props[p]) === -1) {
  799-                item[p].push(props[p]);
  800-              }
  801-            }
  802-          } else {
  803-            item[p] = props[p];
  804-          }
  805-        }
  806-      }
  807-    };
  808-
  809-    this.addItem = function (item) {
  810-      var cellId = item.id,
  811-        coords = instance.utils.cellCoords(cellId);
  812-
  813-      item.row = coords.row;
  814-      item.col = coords.col;
  815-
  816-      var cellExist = instance.matrix.data.filter(function (cell) {
  817-        return cell.id === cellId;
  818-      })[0];
  819-
  820-      if (!cellExist) {
  821-        instance.matrix.data.push(item);
  822-      } else {
  823-        instance.matrix.updateItem(cellExist, item);
  824-      }
  825-
  826-      return instance.matrix.getItem(cellId);
  827-    };
  828-
  829-
  830-    this.updateElementItem = function (element, props) {
  831-      var id = element.getAttribute('id'),
  832-        item = instance.matrix.getItem(id);
  833-
  834-      instance.matrix.updateItem(item, props);
  835-    };
  836-
  837-    this.getDependencies = function (id) {
  838-      var getDependencies = function (id) {
  839-        var filtered = instance.matrix.data.filter(function (cell) {
  840-          if (cell.deps) {
  841-            return cell.deps.indexOf(id) > -1;
  842-          }
  843-        });
  844-
  845-        var deps = [];
  846-        filtered.forEach(function (cell) {
  847-          if (deps.indexOf(cell.id) === -1) {
  848-            deps.push(cell.id);
  849-          }
  850-        });
  851-
  852-        return deps;
  853-      };
  854-
  855-      var allDependencies = [];
  856-
  857-      var getTotalDependencies = function (id) {
  858-        var deps = getDependencies(id);
  859-
  860-        if (deps.length) {
  861-          deps.forEach(function (refId) {
  862-            if (allDependencies.indexOf(refId) === -1) {
  863-              allDependencies.push(refId);
  864-
  865-              var item = instance.matrix.getItem(refId);
  866-              if (item.deps.length) {
  867-                getTotalDependencies(refId);
  868-              }
  869-            }
  870-          });
  871-        }
  872-      };
  873-
  874-      getTotalDependencies(id);
  875-
  876-      return allDependencies;
  877-    };
  878-
  879-    this.getElementDependencies = function (element) {
  880-      return instance.matrix.getDependencies(element.getAttribute('id'));
  881-    };
  882-
  883-    var recalculateElementDependencies = function (element) {
  884-      var allDependencies = instance.matrix.getElementDependencies(element),
  885-        id = element.getAttribute('id');
  886-
  887-      allDependencies.forEach(function (refId) {
  888-        var item = instance.matrix.getItem(refId);
  889-        if (item && item.formula) {
  890-          var refElement = document.getElementById(refId);
  891-          calculateElementFormula(item.formula, refElement);
  892-        }
  893-      });
  894-    };
  895-
  896-    var calculateElementFormula = function (formula, element) {
  897-      // to avoid double translate formulas, update item data in parser
  898-      var parsed = parse(formula, element),
  899-        value = parsed.result,
  900-        error = parsed.error,
  901-        nodeName = element.nodeName.toUpperCase();
  902-
  903-      instance.matrix.updateElementItem(element, {value: value, error: error});
  904-
  905-      if (['INPUT'].indexOf(nodeName) === -1) {
  906-        element.innerText = value || error;
  907-      }
  908-
  909-      element.value = value || error;
  910-
  911-      return parsed;
  912-    };
  913-
  914-    /**
  915-     * register new found element to matrix
  916-     * @param {Element} element
  917-     * @returns {Object}
  918-     */
  919-    var registerElementInMatrix = function (element) {
  920-
  921-      var id = element.getAttribute('id'),
  922-        formula = element.getAttribute('data-formula');
  923-
  924-      if (formula) {
  925-        // add item with basic properties to data array
  926-        instance.matrix.addItem({
  927-          id: id,
  928-          formula: formula
  929-        });
  930-
  931-        calculateElementFormula(formula, element);
  932-      }
  933-
  934-    };
  935-
  936-    /**
  937-     * register events for elements
  938-     * @param element
  939-     */
  940-    var registerElementEvents = function (element) {
  941-      var id = element.getAttribute('id');
  942-
  943-      // on db click show formula
  944-      element.addEventListener('dblclick', function () {
  945-        var item = instance.matrix.getItem(id);
  946-
  947-        if (item && item.formula) {
  948-          item.formulaEdit = true;
  949-          element.value = '=' + item.formula;
  950-        }
  951-      });
  952-
  953-      element.addEventListener('blur', function () {
  954-        var item = instance.matrix.getItem(id);
  955-
  956-        if (item) {
  957-          if (item.formulaEdit) {
  958-            element.value = item.value || item.error;
  959-          }
  960-
  961-          item.formulaEdit = false;
  962-        }
  963-      });
  964-
  965-      // if pressed ESC restore original value
  966-      element.addEventListener('keyup', function (event) {
  967-        switch (event.keyCode) {
  968-          case 13: // ENTER
  969-          case 27: // ESC
  970-            // leave cell
  971-            listen();
  972-            break;
  973-        }
  974-      });
  975-
  976-      // re-calculate formula if ref cells value changed
  977-      element.addEventListener('change', function () {
  978-        // reset and remove item
  979-        instance.matrix.removeItem(id);
  980-
  981-        // check if inserted text could be the formula
  982-        var value = element.value;
  983-
  984-        if (value[0] === '=') {
  985-          element.setAttribute('data-formula', value.substr(1));
  986-          registerElementInMatrix(element);
  987-        }
  988-
  989-        // get ref cells and re-calculate formulas
  990-        recalculateElementDependencies(element);
  991-      });
  992-    };
  993-
  994-    this.scan = function () {
  995-      var $totalElements = rootElement.querySelectorAll(formElements);
  996-      [].slice.call($totalElements).forEach(function ($item) {
  997-        registerElementInMatrix($item);
  998-        registerElementEvents($item);
  999-      });
 1000-    };
 1001-  };
 1002-
 1003-  var utils = {
 1004-    isArray: function (value) {
 1005-      return Object.prototype.toString.call(value) === '[object Array]';
 1006-    },
 1007-
 1008-    isNumber: function (value) {
 1009-      return Object.prototype.toString.call(value) === '[object Number]';
 1010-    },
 1011-
 1012-    isString: function (value) {
 1013-      return Object.prototype.toString.call(value) === '[object String]';
 1014-    },
 1015-
 1016-    isFunction: function (value) {
 1017-      return Object.prototype.toString.call(value) === '[object Function]';
 1018-    },
 1019-
 1020-    isUndefined: function (value) {
 1021-      return Object.prototype.toString.call(value) === '[object Undefined]';
 1022-    },
 1023-
 1024-    isNull: function (value) {
 1025-      return Object.prototype.toString.call(value) === '[object Null]';
 1026-    },
 1027-
 1028-    isSet: function (value) {
 1029-      return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
 1030-    },
 1031-
 1032-    getCellAlphaNum: function (cell) {
 1033-      var num = cell.match(/\d+$/),
 1034-        alpha = cell.replace(num, '');
 1035-
 1036-      return {
 1037-        alpha: alpha,
 1038-        num: parseInt(num[0], 10)
 1039-      }
 1040-    },
 1041-
 1042-    toNum: function (chr) {
 1043-      chr = instance.utils.clearFormula(chr);
 1044-      var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
 1045-
 1046-      for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
 1047-        result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
 1048-      }
 1049-
 1050-      if (result) {
 1051-        --result;
 1052-      }
 1053-
 1054-      return result;
 1055-    },
 1056-
 1057-    toChar: function (num) {
 1058-      var s = '';
 1059-
 1060-      while (num >= 0) {
 1061-        s = String.fromCharCode(num % 26 + 97) + s;
 1062-        num = Math.floor(num / 26) - 1;
 1063-      }
 1064-
 1065-      return s.toUpperCase();
 1066-    },
 1067-
 1068-    cellCoords: function (cell) {
 1069-      var num = cell.match(/\d+$/),
 1070-        alpha = cell.replace(num, '');
 1071-
 1072-      return {
 1073-        row: parseInt(num[0], 10) - 1,
 1074-        col: instance.utils.toNum(alpha)
 1075-      };
 1076-    },
 1077-
 1078-    clearFormula: function (formula) {
 1079-      return formula.replace(/\$/g, '');
 1080-    },
 1081-
 1082-    translateCellCoords: function (coords) {
 1083-      return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
 1084-    },
 1085-
 1086-    iterateCells: function (startCell, endCell, callback) {
 1087-      var result = {
 1088-        index: [], // list of cell index: A1, A2, A3
 1089-        value: []  // list of cell value
 1090-      };
 1091-
 1092-      var cols = {
 1093-        start: 0,
 1094-        end: 0
 1095-      };
 1096-
 1097-      if (endCell.col >= startCell.col) {
 1098-        cols = {
 1099-          start: startCell.col,
 1100-          end: endCell.col
 1101-        };
 1102-      } else {
 1103-        cols = {
 1104-          start: endCell.col,
 1105-          end: startCell.col
 1106-        };
 1107-      }
 1108-
 1109-      var rows = {
 1110-        start: 0,
 1111-        end: 0
 1112-      };
 1113-
 1114-      if (endCell.row >= startCell.row) {
 1115-        rows = {
 1116-          start: startCell.row,
 1117-          end: endCell.row
 1118-        };
 1119-      } else {
 1120-        rows = {
 1121-          start: endCell.row,
 1122-          end: startCell.row
 1123-        };
 1124-      }
 1125-
 1126-      for (var column = cols.start; column <= cols.end; column++) {
 1127-        for (var row = rows.start; row <= rows.end; row++) {
 1128-          var cellIndex = instance.utils.toChar(column) + (row + 1),
 1129-            cellValue = instance.helper.cellValue.call(this, cellIndex);
 1130-
 1131-          result.index.push(cellIndex);
 1132-          result.value.push(cellValue);
 1133-        }
 1134-      }
 1135-
 1136-      if (instance.utils.isFunction(callback)) {
 1137-        return callback.apply(callback, [result]);
 1138-      } else {
 1139-        return result;
 1140-      }
 1141-    },
 1142-
 1143-    sort: function (rev) {
 1144-      return function (a, b) {
 1145-        return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
 1146-      }
 1147-    }
 1148-  };
 1149-
 1150-  var helper = {
 1151-    SUPPORTED_FORMULAS: [
 1152-      'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
 1153-      'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
 1154-      'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
 1155-      'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
 1156-      'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
 1157-      'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
 1158-      'IF', 'INT', 'ISEVEN', 'ISODD',
 1159-      'LN', 'LOG', 'LOG10',
 1160-      'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
 1161-      'NOT',
 1162-      'ODD', 'OR',
 1163-      'PI', 'POWER',
 1164-      'ROUND', 'ROUNDDOWN', 'ROUNDUP',
 1165-      'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
 1166-      'TAN', 'TANH', 'TRUE', 'TRUNC',
 1167-      'XOR'
 1168-    ],
 1169-
 1170-    number: function (num) {
 1171-      switch (typeof num) {
 1172-        case 'number':
 1173-          return num;
 1174-        case 'string':
 1175-          if (!isNaN(num)) {
 1176-            return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
 1177-          }
 1178-      }
 1179-
 1180-      return num;
 1181-    },
 1182-
 1183-    string: function (str) {
 1184-      return str.substring(1, str.length - 1);
 1185-    },
 1186-
 1187-    numberInverted: function (num) {
 1188-      return this.number(num) * (-1);
 1189-    },
 1190-
 1191-    specialMatch: function (type, exp1, exp2) {
 1192-      var result;
 1193-
 1194-      switch (type) {
 1195-        case '&':
 1196-          result = exp1.toString() + exp2.toString();
 1197-          break;
 1198-      }
 1199-      return result;
 1200-    },
 1201-
 1202-    logicMatch: function (type, exp1, exp2) {
 1203-      var result;
 1204-
 1205-      switch (type) {
 1206-        case '=':
 1207-          result = (exp1 === exp2);
 1208-          break;
 1209-
 1210-        case '>':
 1211-          result = (exp1 > exp2);
 1212-          break;
 1213-
 1214-        case '<':
 1215-          result = (exp1 < exp2);
 1216-          break;
 1217-
 1218-        case '>=':
 1219-          result = (exp1 >= exp2);
 1220-          break;
 1221-
 1222-        case '<=':
 1223-          result = (exp1 === exp2);
 1224-          break;
 1225-
 1226-        case '<>':
 1227-          result = (exp1 != exp2);
 1228-          break;
 1229-
 1230-        case 'NOT':
 1231-          result = (exp1 != exp2);
 1232-          break;
 1233-      }
 1234-
 1235-      return result;
 1236-    },
 1237-
 1238-    mathMatch: function (type, number1, number2) {
 1239-      var result;
 1240-
 1241-      number1 = helper.number(number1);
 1242-      number2 = helper.number(number2);
 1243-
 1244-      if (isNaN(number1) || isNaN(number2)) {
 1245-        throw Error('VALUE');
 1246-      }
 1247-
 1248-      switch (type) {
 1249-        case '+':
 1250-          result = number1 + number2;
 1251-          break;
 1252-        case '-':
 1253-          result = number1 - number2;
 1254-          break;
 1255-        case '/':
 1256-          result = number1 / number2;
 1257-          if (result == Infinity) {
 1258-            throw Error('DIV_ZERO');
 1259-          } else if (isNaN(result)) {
 1260-            throw Error('VALUE');
 1261-          }
 1262-          break;
 1263-        case '*':
 1264-          result = number1 * number2;
 1265-          break;
 1266-        case '^':
 1267-          result = Math.pow(number1, number2);
 1268-          break;
 1269-      }
 1270-
 1271-      return result;
 1272-    },
 1273-
 1274-    callFunction: function (fn, args) {
 1275-      fn = fn.toUpperCase();
 1276-      args = args || [];
 1277-
 1278-      if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
 1279-        if (instance.formulas[fn]) {
 1280-          return instance.formulas[fn].apply(this, args);
 1281-        }
 1282-      }
 1283-
 1284-      throw Error('NAME');
 1285-    },
 1286-
 1287-    callVariable: function (args) {
 1288-      args = args || [];
 1289-      var str = args[0];
 1290-
 1291-      if (str) {
 1292-        str = str.toUpperCase();
 1293-        if (instance.formulas[str]) {
 1294-          return ((typeof instance.formulas[str] === 'function') ? instance.formulas[str].apply(this, args) : instance.formulas[str]);
 1295-        }
 1296-      }
 1297-
 1298-      throw Error('NAME');
 1299-    },
 1300-
 1301-    cellValue: function (cell) {
 1302-      var value,
 1303-        fnCellValue = instance.custom.cellValue,
 1304-        element = this,
 1305-        item = instance.matrix.getItem(cell);
 1306-
 1307-      // check if custom cellValue fn exists
 1308-      if (instance.utils.isFunction(fnCellValue)) {
 1309-
 1310-        var cellCoords = instance.utils.cellCoords(cell),
 1311-          cellId = instance.utils.translateCellCoords({row: element.row, col: element.col});
 1312-
 1313-        // get value
 1314-        value = item ? item.value : fnCellValue(cellCoords.row, cellCoords.col);
 1315-
 1316-        if (instance.utils.isNull(value)) {
 1317-          value = 0;
 1318-        }
 1319-
 1320-        if (cellId) {
 1321-          //update dependencies
 1322-          instance.matrix.updateItem(cellId, {deps: [cell]});
 1323-        }
 1324-
 1325-      } else {
 1326-
 1327-        // get value
 1328-        value = item ? item.value : document.getElementById(cell).value;
 1329-
 1330-        //update dependencies
 1331-        instance.matrix.updateElementItem(element, {deps: [cell]});
 1332-      }
 1333-
 1334-      // check references error
 1335-      if (item && item.deps) {
 1336-        if (item.deps.indexOf(cellId) !== -1) {
 1337-          throw Error('REF');
 1338-        }
 1339-      }
 1340-
 1341-      // check if any error occurs
 1342-      if (item && item.error) {
 1343-        throw Error(item.error);
 1344-      }
 1345-
 1346-      // return value if is set
 1347-      if (instance.utils.isSet(value)) {
 1348-        var result = instance.helper.number(value);
 1349-
 1350-        return !isNaN(result) ? result : value;
 1351-      }
 1352-
 1353-      // cell is not available
 1354-      throw Error('NOT_AVAILABLE');
 1355-    },
 1356-
 1357-    cellRangeValue: function (start, end) {
 1358-      var fnCellValue = instance.custom.cellValue,
 1359-        coordsStart = instance.utils.cellCoords(start),
 1360-        coordsEnd = instance.utils.cellCoords(end),
 1361-        element = this;
 1362-
 1363-      // iterate cells to get values and indexes
 1364-      var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd),
 1365-        result = [];
 1366-
 1367-      // check if custom cellValue fn exists
 1368-      if (instance.utils.isFunction(fnCellValue)) {
 1369-
 1370-        var cellId = instance.utils.translateCellCoords({row: element.row, col: element.col});
 1371-
 1372-        //update dependencies
 1373-        instance.matrix.updateItem(cellId, {deps: cells.index});
 1374-
 1375-      } else {
 1376-
 1377-        //update dependencies
 1378-        instance.matrix.updateElementItem(element, {deps: cells.index});
 1379-      }
 1380-
 1381-      result.push(cells.value);
 1382-      return result;
 1383-    },
 1384-
 1385-    fixedCellValue: function (id) {
 1386-      id = id.replace(/\$/g, '');
 1387-      return instance.helper.cellValue.call(this, id);
 1388-    },
 1389-
 1390-    fixedCellRangeValue: function (start, end) {
 1391-      start = start.replace(/\$/g, '');
 1392-      end = end.replace(/\$/g, '');
 1393-
 1394-      return instance.helper.cellRangeValue.call(this, start, end);
 1395-    }
 1396-  };
 1397-
 1398-  var parse = function (formula, element) {
 1399-    var result = null,
 1400-      error = null;
 1401-
 1402-    try {
 1403-
 1404-      parser.setObj(element);
 1405-      result = parser.parse(formula);
 1406-
 1407-      var id;
 1408-
 1409-      if (element instanceof HTMLElement) {
 1410-        id = element.getAttribute('id');
 1411-      } else if (element && element.id) {
 1412-        id = element.id;
 1413-      }
 1414-
 1415-      var deps = instance.matrix.getDependencies(id);
 1416-
 1417-      if (deps.indexOf(id) !== -1) {
 1418-        result = null;
 1419-
 1420-        deps.forEach(function (id) {
 1421-          instance.matrix.updateItem(id, {value: null, error: Exception.get('REF')});
 1422-        });
 1423-
 1424-        throw Error('REF');
 1425-      }
 1426-
 1427-    } catch (ex) {
 1428-
 1429-      var message = Exception.get(ex.message);
 1430-
 1431-      if (message) {
 1432-        error = message;
 1433-      } else {
 1434-        error = Exception.get('ERROR');
 1435-      }
 1436-    }
 1437-
 1438-    return {
 1439-      error: error,
 1440-      result: result
 1441-    }
 1442-  };
 1443-
 1444-  var init = function () {
 1445-    instance = this;
 1446-
 1447-    parser = new FormulaParser(instance);
 1448-
 1449-    instance.formulas = Formula;
 1450-    instance.matrix = new Matrix();
 1451-
 1452-    instance.custom = {};
 1453-
 1454-    if (rootElement) {
 1455-      instance.matrix.scan();
 1456-    }
 1457-  };
 1458-
 1459-  return {
 1460-    init: init,
 1461-    utils: utils,
 1462-    helper: helper,
 1463-    parse: parse
 1464-  };
 1465-
 1466-});
 1467diff --git a/lib/formulajs/formula.js b/lib/formulajs/formula.js
 1468deleted file mode 100644
 1469index 53ba1cc..0000000
 1470--- a/lib/formulajs/formula.js
 1471+++ /dev/null
 1472@@ -1,5828 +0,0 @@
 1473-// Copyright (c) 2012 Sutoiku, Inc.
 1474-
 1475-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 1476-
 1477-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 1478-
 1479-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 1480-
 1481-// Some algorithms have been ported from Apache OpenOffice:
 1482-
 1483-/**************************************************************
 1484- *
 1485- * Licensed to the Apache Software Foundation (ASF) under one
 1486- * or more contributor license agreements.  See the NOTICE file
 1487- * distributed with this work for additional information
 1488- * regarding copyright ownership.  The ASF licenses this file
 1489- * to you under the Apache License, Version 2.0 (the
 1490- * "License"); you may not use this file except in compliance
 1491- * with the License.  You may obtain a copy of the License at
 1492- *
 1493- *   http://www.apache.org/licenses/LICENSE-2.0
 1494- *
 1495- * Unless required by applicable law or agreed to in writing,
 1496- * software distributed under the License is distributed on an
 1497- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 1498- * KIND, either express or implied.  See the License for the
 1499- * specific language governing permissions and limitations
 1500- * under the License.
 1501- *
 1502- *************************************************************/
 1503-/*jslint evil: true*/
 1504-/*global define */
 1505-
 1506-(function () {
 1507-  var root = this;
 1508-
 1509-  var Formula = root.Formula = {};
 1510-  var _ = root._;
 1511-  var numeric = root.numeric;
 1512-  var numeral = root.numeral;
 1513-  var jStat = root.jStat;
 1514-  var moment = root.moment;
 1515-  var lodash = _;
 1516-  var md5 = root.md5;
 1517-  var _s = _.str;
 1518-
 1519-  if (typeof exports !== "undefined") {
 1520-    module.exports = exportModule(
 1521-      require('numeric'),
 1522-      require('numeral'),
 1523-      require('jStat'),
 1524-      require('moment'),
 1525-      require('lodash'),
 1526-      require('underscore.string'),
 1527-      require('blueimp-md5')
 1528-    );
 1529-  } else if (typeof define === "function" && define.amd) {
 1530-    define(
 1531-      'formula',
 1532-      ['numeric', 'numeral', 'jstat', 'moment', 'lodash', 'underscore.string', 'md5'],
 1533-      exportModule
 1534-    );
 1535-  } else {
 1536-    Formula = exportModule(numeric, numeral, jStat, moment, lodash, _s, md5);
 1537-    return Formula;
 1538-  }
 1539-
 1540-  function exportModule(numeric, numeral, jStat, moment, _, _s, md5) {
 1541-    var MEMOIZED_FACT = [];
 1542-
 1543-    var SQRT2PI = 2.5066282746310002;
 1544-
 1545-    var WEEK_STARTS = [
 1546-      undefined,
 1547-      0,
 1548-      1,
 1549-      undefined,
 1550-      undefined,
 1551-      undefined,
 1552-      undefined,
 1553-      undefined,
 1554-      undefined,
 1555-      undefined,
 1556-      undefined,
 1557-      undefined,
 1558-      1,
 1559-      2,
 1560-      3,
 1561-      4,
 1562-      5,
 1563-      6,
 1564-      0
 1565-    ];
 1566-
 1567-    var WEEK_TYPES = [
 1568-      [],
 1569-      [1, 2, 3, 4, 5, 6, 7],
 1570-      [7, 1, 2, 3, 4, 5, 6],
 1571-      [6, 0, 1, 2, 3, 4, 5],
 1572-      [],
 1573-      [],
 1574-      [],
 1575-      [],
 1576-      [],
 1577-      [],
 1578-      [],
 1579-      [7, 1, 2, 3, 4, 5, 6],
 1580-      [6, 7, 1, 2, 3, 4, 5],
 1581-      [5, 6, 7, 1, 2, 3, 4],
 1582-      [4, 5, 6, 7, 1, 2, 3],
 1583-      [3, 4, 5, 6, 7, 1, 2],
 1584-      [2, 3, 4, 5, 6, 7, 1],
 1585-      [1, 2, 3, 4, 5, 6, 7]
 1586-    ];
 1587-
 1588-    var WEEKEND_TYPES = [
 1589-      [],
 1590-      [6, 0],
 1591-      [0, 1],
 1592-      [1, 2],
 1593-      [2, 3],
 1594-      [3, 4],
 1595-      [4, 5],
 1596-      [5, 6],
 1597-      undefined,
 1598-      undefined,
 1599-      undefined,
 1600-      [0],
 1601-      [1],
 1602-      [2],
 1603-      [3],
 1604-      [4],
 1605-      [5],
 1606-      [6]
 1607-    ];
 1608-
 1609-    var simplifyArguments = function (arguments) {
 1610-      for (var prop in arguments) {
 1611-        if (_.isArray(arguments[prop])) {
 1612-          arguments[prop] = Formula.FLATTEN(arguments[prop]);
 1613-        }
 1614-      }
 1615-      return arguments;
 1616-    };
 1617-
 1618-    // Override some functions
 1619-    Formula.UNIQUE = function () {
 1620-      return _.unique(arguments);
 1621-    };
 1622-
 1623-    Formula.FLATTEN = function () {
 1624-      return _.flatten(arguments);
 1625-    };
 1626-
 1627-    // Generate a callback function
 1628-    Formula.FUNCTION = function () {
 1629-      var args = Array.prototype.slice.call(arguments);
 1630-      var expression = args[args.length - 1];
 1631-      var regexp = /(\w+)\(/g;
 1632-      var newExpression = expression.replace(regexp, function () {
 1633-        return "Formulae." + arguments[0];
 1634-      });
 1635-
 1636-      args[args.length - 1] = "return " + newExpression + ";";
 1637-      if (newExpression !== expression) {
 1638-        args.unshift('Formulae');
 1639-      }
 1640-
 1641-      return  Function.apply(null, args);
 1642-    };
 1643-
 1644-    // Moment functions
 1645-    Formula.MOMENT = function (timestamp, format) {
 1646-      return moment(timestamp).format(format);
 1647-    };
 1648-
 1649-    Formula.MOMENTADD = function (start_date, period, number) {
 1650-      return moment(start_date).add(period, number);
 1651-    };
 1652-
 1653-    Formula.MOMENTDIFF = function (start_date, end_date, period) {
 1654-      return moment(end_date).diff(moment.utc(start_date), period);
 1655-    };
 1656-
 1657-    Formula.MOMENTSUB = function (start_date, period, number) {
 1658-      return moment(start_date).subtract(period, number);
 1659-    };
 1660-
 1661-    Formula.MOMENTUTC = function (timestamp, format) {
 1662-      return moment.utc(timestamp).format(format);
 1663-    };
 1664-
 1665-    Formula.MOMENTUTCADD = function (start_date, period, number) {
 1666-      return moment.utc(start_date).add(period, number);
 1667-    };
 1668-
 1669-    Formula.MOMENTUTCDIFF = function (start_date, end_date, period) {
 1670-      return moment.utc(end_date).diff(moment.utc(start_date), period);
 1671-    };
 1672-
 1673-    Formula.MOMENTUTCSUB = function (start_date, period, number) {
 1674-      return moment.utc(start_date).subtract(period, number);
 1675-    };
 1676-
 1677-    Formula.MOMENTUNIX = function (unixTime) {
 1678-      return moment.unix(unixTime).toDate();
 1679-    };
 1680-
 1681-    Formula.MOMENTFORMAT = function (date, format) {
 1682-      return moment(date).format(format);
 1683-    };
 1684-
 1685-    Formula.MOMENTISLEAPYEAR = function (date, format) {
 1686-      return moment(date, format).isLeapYear();
 1687-    };
 1688-
 1689-    Formula.MOMENTISDST = function (date, format) {
 1690-      return moment(date, format).isDST();
 1691-    };
 1692-
 1693-    Formula.MOMENTSTARTOF = function (date, units, format) {
 1694-      return moment(date, format).startOf(units).toDate();
 1695-    };
 1696-
 1697-    Formula.MOMENTENDOF = function (date, units, format) {
 1698-      return moment(date, format).endOf(units).toDate();
 1699-    };
 1700-
 1701-    Formula.MOMENTISAFTER = function (date1, date2, format) {
 1702-      return moment(date1, format).isAfter(moment(date2, format));
 1703-    };
 1704-
 1705-    Formula.MOMENTISBEFORE = function (date1, date2, format) {
 1706-      return moment(date1, format).isBefore(moment(date2, format));
 1707-    };
 1708-
 1709-    Formula.INTERVAL = function (second) {
 1710-      var year  = Math.floor(second/946080000);
 1711-      second    = second%946080000;
 1712-      var month = Math.floor(second/2592000);
 1713-      second    = second%2592000;
 1714-      var day   = Math.floor(second/86400);
 1715-      second    = second%86400;
 1716-
 1717-      var hour  = Math.floor(second/3600);
 1718-      second    = second%3600;
 1719-      var min   = Math.floor(second/60);
 1720-      second    = second%60;
 1721-      var sec   = second;
 1722-
 1723-      year  = (year  > 0) ? year  + 'Y' : '';
 1724-      month = (month > 0) ? month + 'M' : '';
 1725-      day   = (day   > 0) ? day   + 'D' : '';
 1726-      hour  = (hour  > 0) ? hour  + 'H' : '';
 1727-      min   = (min   > 0) ? min   + 'M' : '';
 1728-      sec   = (sec   > 0) ? sec   + 'S' : '';
 1729-
 1730-      return 'P' + year + month + day +
 1731-        'T' + hour + min + sec;
 1732-    };
 1733-
 1734-    // Custom Functions
 1735-    Formula.ARGSCONCAT = function (args) {
 1736-      var result = [];
 1737-      for (var i = 0; i < args.length; i++) {
 1738-        result = result.concat(args[i]);
 1739-      }
 1740-      return result;
 1741-    };
 1742-
 1743-    Formula.ARGSTOARRAY = function (args) {
 1744-      return Array.prototype.slice.call(args, 0);
 1745-    };
 1746-
 1747-    Formula.CLEANFLOAT = function (number) {
 1748-      var power = Math.pow(10, 14);
 1749-      return Math.round(number * power) / power;
 1750-    };
 1751-
 1752-    Formula.COUNTIN = function (range, value) {
 1753-      var result = 0;
 1754-      for (var i = 0; i < range.length; i++) {
 1755-        if (range[i] === value) {
 1756-          result++;
 1757-        }
 1758-      }
 1759-      return result;
 1760-    };
 1761-
 1762-    Formula.FINDFIELD = function(database, title) {
 1763-      var index = null;
 1764-      for (var i = 0; i < database.length; i++) {
 1765-        if (database[i][0] === title) {
 1766-          index = i;
 1767-          break;
 1768-        }
 1769-      }
 1770-
 1771-      // Return error if the input field title is incorrect
 1772-      if (index == null) {
 1773-        return '#VALUE!';
 1774-      }
 1775-      return index;
 1776-    };
 1777-
 1778-    Formula.FINDRESULTINDEX = function(database, criteria) {
 1779-      var maxCriteriaLength = criteria[0].length;
 1780-      for (var i = 1; i < criteria.length; i++) {
 1781-        if (criteria[i].length > maxCriteriaLength) {
 1782-          maxCriteriaLength = criteria[i].length;
 1783-        }
 1784-      }
 1785-      var columnResultIndexes = [];
 1786-      for (i = 1; i < maxCriteriaLength; i++) {
 1787-        var rowResultIndexes = [];
 1788-        for (var j = 0; j < criteria.length; j++) {
 1789-          if (criteria[j].length < maxCriteriaLength) {
 1790-            continue;
 1791-          }
 1792-          var criteriaTitle = criteria[j][0];
 1793-          var criteriaIndex = Formula.FINDFIELD(database, criteriaTitle);
 1794-          var criteriaValues = _.rest(database[criteriaIndex]);
 1795-          var count = 0;
 1796-          var singleResultIndexes = [];
 1797-          for (var k = 0; k < criteriaValues.length; k++) {
 1798-            if (eval(criteriaValues[k] + criteria[j][i])) {
 1799-              singleResultIndexes[count++] = k;
 1800-            }
 1801-          }
 1802-          rowResultIndexes[j] = singleResultIndexes;
 1803-        }
 1804-        columnResultIndexes[i - 1] = _.intersection.apply(_, rowResultIndexes);
 1805-      }
 1806-
 1807-      var resultIndexes = _.union.apply(_, columnResultIndexes);
 1808-      return resultIndexes;
 1809-    };
 1810-
 1811-    // Database functions
 1812-    Formula.DAVERAGE = function(database, field, criteria) {
 1813-      // Return error if field is not a number and not a string
 1814-      if (isNaN(field) && (typeof field !== "string")) {
 1815-        return '#VALUE!';
 1816-      }
 1817-
 1818-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1819-      var targetFields = [];
 1820-      if (typeof field === "string") {
 1821-        var index = Formula.FINDFIELD(database, field);
 1822-        targetFields = _.rest(database[index]);
 1823-      } else {
 1824-        targetFields = _.rest(database[field]);
 1825-      }
 1826-      var sum = 0;
 1827-      for (var i = 0; i < resultIndexes.length; i++) {
 1828-        sum += targetFields[resultIndexes[i]];
 1829-      }
 1830-      var average = Formula.IF(resultIndexes.length === 0, "#DIV/0!", sum / resultIndexes.length);
 1831-      return average;
 1832-    };
 1833-
 1834-    Formula.DCOUNT = function(database, field, criteria) {
 1835-      // Return error if field is not a number and not a string
 1836-      if (isNaN(field) && (typeof field !== "string")) {
 1837-        return '#VALUE!';
 1838-      }
 1839-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1840-      var targetFields = [];
 1841-      if (typeof field === "string") {
 1842-        var index = Formula.FINDFIELD(database, field);
 1843-        targetFields = _.rest(database[index]);
 1844-      } else {
 1845-        targetFields = _.rest(database[field]);
 1846-      }
 1847-      var targetValues = [];
 1848-      for (var i = 0; i < resultIndexes.length; i++) {
 1849-        targetValues[i] = targetFields[resultIndexes[i]];
 1850-      }
 1851-      return Formula.COUNT(targetValues);
 1852-    };
 1853-
 1854-    Formula.DCOUNTA = function(database, field, criteria) {
 1855-      // Return error if field is not a number and not a string
 1856-      if (isNaN(field) && (typeof field !== "string")) {
 1857-        return '#VALUE!';
 1858-      }
 1859-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1860-      var targetFields = [];
 1861-      if (typeof field === "string") {
 1862-        var index = Formula.FINDFIELD(database, field);
 1863-        targetFields = _.rest(database[index]);
 1864-      } else {
 1865-        targetFields = _.rest(database[field]);
 1866-      }
 1867-      var targetValues = [];
 1868-      for (var i = 0; i < resultIndexes.length; i++) {
 1869-        targetValues[i] = targetFields[resultIndexes[i]];
 1870-      }
 1871-      return Formula.COUNTA(targetValues);
 1872-    };
 1873-
 1874-    Formula.DGET = function(database, field, criteria) {
 1875-      // Return error if field is not a number and not a string
 1876-      if (isNaN(field) && (typeof field !== "string")) {
 1877-        return '#VALUE!';
 1878-      }
 1879-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1880-      var targetFields = [];
 1881-      if (typeof field === "string") {
 1882-        var index = Formula.FINDFIELD(database, field);
 1883-        targetFields = _.rest(database[index]);
 1884-      } else {
 1885-        targetFields = _.rest(database[field]);
 1886-      }
 1887-      // Return error if no record meets the criteria
 1888-      if (resultIndexes.length === 0) {
 1889-        return '#VALUE!';
 1890-      }
 1891-      // Returns the #NUM! error value because more than one record meets the
 1892-      // criteria
 1893-      if (resultIndexes.length > 1) {
 1894-        return '#NUM!';
 1895-      }
 1896-
 1897-      return targetFields[resultIndexes[0]];
 1898-    };
 1899-
 1900-    Formula.DMAX = function(database, field, criteria) {
 1901-      // Return error if field is not a number and not a string
 1902-      if (isNaN(field) && (typeof field !== "string")) {
 1903-        return '#VALUE!';
 1904-      }
 1905-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1906-      var targetFields = [];
 1907-      if (typeof field === "string") {
 1908-        var index = Formula.FINDFIELD(database, field);
 1909-        targetFields = _.rest(database[index]);
 1910-      } else {
 1911-        targetFields = _.rest(database[field]);
 1912-      }
 1913-      var maxValue = targetFields[resultIndexes[0]];
 1914-      for (var i = 1; i < resultIndexes.length; i++) {
 1915-        if (maxValue < targetFields[resultIndexes[i]]) {
 1916-          maxValue = targetFields[resultIndexes[i]];
 1917-        }
 1918-      }
 1919-      return maxValue;
 1920-    };
 1921-
 1922-    Formula.DMIN = function(database, field, criteria) {
 1923-      // Return error if field is not a number and not a string
 1924-      if (isNaN(field) && (typeof field !== "string")) {
 1925-        return '#VALUE!';
 1926-      }
 1927-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1928-      var targetFields = [];
 1929-      if (typeof field === "string") {
 1930-        var index = Formula.FINDFIELD(database, field);
 1931-        targetFields = _.rest(database[index]);
 1932-      } else {
 1933-        targetFields = _.rest(database[field]);
 1934-      }
 1935-      var minValue = targetFields[resultIndexes[0]];
 1936-      for (var i = 1; i < resultIndexes.length; i++) {
 1937-        if (minValue > targetFields[resultIndexes[i]]) {
 1938-          minValue = targetFields[resultIndexes[i]];
 1939-        }
 1940-      }
 1941-      return minValue;
 1942-    };
 1943-
 1944-    Formula.DPRODUCT = function(database, field, criteria) {
 1945-      // Return error if field is not a number and not a string
 1946-      if (isNaN(field) && (typeof field !== "string")) {
 1947-        return '#VALUE!';
 1948-      }
 1949-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1950-      var targetFields = [];
 1951-      if (typeof field === "string") {
 1952-        var index = Formula.FINDFIELD(database, field);
 1953-        targetFields = _.rest(database[index]);
 1954-      } else {
 1955-        targetFields = _.rest(database[field]);
 1956-      }
 1957-      var targetValues = [];
 1958-      for (var i = 0; i < resultIndexes.length; i++) {
 1959-        targetValues[i] = targetFields[resultIndexes[i]];
 1960-      }
 1961-      targetValues = _.compact(targetValues);
 1962-      var result = 1;
 1963-      for (i = 0; i < targetValues.length; i++) {
 1964-        result *= targetValues[i];
 1965-      }
 1966-      return result;
 1967-    };
 1968-
 1969-    Formula.DSTDEV = function(database, field, criteria) {
 1970-      // Return error if field is not a number and not a string
 1971-      if (isNaN(field) && (typeof field !== "string")) {
 1972-        return '#VALUE!';
 1973-      }
 1974-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1975-      var targetFields = [];
 1976-      if (typeof field === "string") {
 1977-        var index = Formula.FINDFIELD(database, field);
 1978-        targetFields = _.rest(database[index]);
 1979-      } else {
 1980-        targetFields = _.rest(database[field]);
 1981-      }
 1982-      var targetValues = [];
 1983-      for (var i = 0; i < resultIndexes.length; i++) {
 1984-        targetValues[i] = targetFields[resultIndexes[i]];
 1985-      }
 1986-      targetValues = _.compact(targetValues);
 1987-      return Formula.STDEVS(targetValues);
 1988-    };
 1989-
 1990-    Formula.DSTDEVP = function(database, field, criteria) {
 1991-      // Return error if field is not a number and not a string
 1992-      if (isNaN(field) && (typeof field !== "string")) {
 1993-        return '#VALUE!';
 1994-      }
 1995-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 1996-      var targetFields = [];
 1997-      if (typeof field === "string") {
 1998-        var index = Formula.FINDFIELD(database, field);
 1999-        targetFields = _.rest(database[index]);
 2000-      } else {
 2001-        targetFields = _.rest(database[field]);
 2002-      }
 2003-      var targetValues = [];
 2004-      for (var i = 0; i < resultIndexes.length; i++) {
 2005-        targetValues[i] = targetFields[resultIndexes[i]];
 2006-      }
 2007-      targetValues = _.compact(targetValues);
 2008-      return Formula.STDEVP(targetValues);
 2009-    };
 2010-
 2011-    Formula.DSUM = function(database, field, criteria) {
 2012-      // Return error if field is not a number and not a string
 2013-      if (isNaN(field) && (typeof field !== "string")) {
 2014-        return '#VALUE!';
 2015-      }
 2016-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 2017-      var targetFields = [];
 2018-      if (typeof field === "string") {
 2019-        var index = Formula.FINDFIELD(database, field);
 2020-        targetFields = _.rest(database[index]);
 2021-      } else {
 2022-        targetFields = _.rest(database[field]);
 2023-      }
 2024-      var targetValues = [];
 2025-      for (var i = 0; i < resultIndexes.length; i++) {
 2026-        targetValues[i] = targetFields[resultIndexes[i]];
 2027-      }
 2028-      return Formula.SUM(targetValues);
 2029-    };
 2030-
 2031-    Formula.DVAR = function(database, field, criteria) {
 2032-      // Return error if field is not a number and not a string
 2033-      if (isNaN(field) && (typeof field !== "string")) {
 2034-        return '#VALUE!';
 2035-      }
 2036-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 2037-      var targetFields = [];
 2038-      if (typeof field === "string") {
 2039-        var index = Formula.FINDFIELD(database, field);
 2040-        targetFields = _.rest(database[index]);
 2041-      } else {
 2042-        targetFields = _.rest(database[field]);
 2043-      }
 2044-      var targetValues = [];
 2045-      for (var i = 0; i < resultIndexes.length; i++) {
 2046-        targetValues[i] = targetFields[resultIndexes[i]];
 2047-      }
 2048-      return Formula.VARS(targetValues);
 2049-    };
 2050-
 2051-    Formula.DVARP = function(database, field, criteria) {
 2052-      // Return error if field is not a number and not a string
 2053-      if (isNaN(field) && (typeof field !== "string")) {
 2054-        return '#VALUE!';
 2055-      }
 2056-      var resultIndexes = Formula.FINDRESULTINDEX(database, criteria);
 2057-      var targetFields = [];
 2058-      if (typeof field === "string") {
 2059-        var index = Formula.FINDFIELD(database, field);
 2060-        targetFields = _.rest(database[index]);
 2061-      } else {
 2062-        targetFields = _.rest(database[field]);
 2063-      }
 2064-      var targetValues = [];
 2065-      for (var i = 0; i < resultIndexes.length; i++) {
 2066-        targetValues[i] = targetFields[resultIndexes[i]];
 2067-      }
 2068-      return Formula.VARP(targetValues);
 2069-    };
 2070-
 2071-    Formula.GETJSON = function (file) {
 2072-      var request = new XMLHttpRequest();
 2073-      request.open('GET', file, false);
 2074-      request.send(null);
 2075-      if (request.status === 200) {
 2076-        return JSON.parse(request.responseText);
 2077-      }
 2078-    };
 2079-
 2080-
 2081-    // Date functions
 2082-    Formula.DATE = function () {
 2083-      if (!arguments.length) {
 2084-        return new Date();
 2085-      }
 2086-
 2087-      if (arguments.length === 1) {
 2088-        return new Date(arguments[0]);
 2089-      }
 2090-
 2091-      var args = arguments;
 2092-      args[1] = args[1] - 1; // Monthes are between 0 and 11.
 2093-      return new (Date.bind.apply(Date, [Date].concat([].splice.call(args, 0))))();
 2094-    };
 2095-
 2096-    Formula.DATEVALUE = function (date_text) {
 2097-      return Math.ceil((moment(date_text) - moment('1900-1-1')) / 86400000) + 2;
 2098-    };
 2099-
 2100-    Formula.DAY = function (date) {
 2101-      return new Date(date).getDate();
 2102-    };
 2103-
 2104-    Formula.DAYS = function (end_date, start_date) {
 2105-      return moment(new Date(end_date)).diff(moment(new Date(start_date)), 'days');
 2106-    };
 2107-
 2108-    Formula.DAYS360 = function (start_date, end_date, method) {
 2109-      var start = moment(new Date(start_date));
 2110-      var end = moment(new Date(end_date));
 2111-      var smd = 31;
 2112-      var emd = 31;
 2113-      var sd = start.date();
 2114-      var ed = end.date();
 2115-      if (method) {
 2116-        sd = (sd === 31) ? 30 : sd;
 2117-        ed = (ed === 31) ? 30 : ed;
 2118-      }
 2119-      else {
 2120-        if (start.month() === 1) {
 2121-          smd = start.daysInMonth();
 2122-        }
 2123-        if (end.month() === 1) {
 2124-          emd = end.daysInMonth();
 2125-        }
 2126-        sd = (sd === smd) ? 30 : sd;
 2127-        if (sd === 30 || sd === smd) {
 2128-          ed = (ed === emd) ? 30 : ed;
 2129-        }
 2130-      }
 2131-      return 360 * (end.year() - start.year()) + 30 * (end.month() - start.month()) + (ed - sd);
 2132-    };
 2133-
 2134-    Formula.EDATE = function (start_date, months) {
 2135-      return moment(new Date(start_date)).add('months', months).toDate();
 2136-    };
 2137-
 2138-    Formula.EOMONTH = function (start_date, months) {
 2139-      var edate = moment(new Date(start_date)).add('months', months);
 2140-      return new Date(edate.year(), edate.month(), edate.daysInMonth());
 2141-    };
 2142-
 2143-    Formula.FROMNOW = function (timestamp, nosuffix) {
 2144-      return moment(new Date(timestamp)).fromNow(nosuffix);
 2145-    };
 2146-
 2147-    Formula.HOUR = function (timestamp) {
 2148-      return (timestamp <= 1) ? Math.floor(24 * timestamp) : new Date(timestamp).getHours();
 2149-    };
 2150-
 2151-    Formula.MINUTE = function (timestamp) {
 2152-      return (timestamp <= 1) ? Math.floor(24 * 60 * timestamp) - 60 * Math.floor(24 * timestamp) : new Date(timestamp).getMinutes();
 2153-    };
 2154-
 2155-    Formula.ISOWEEKNUM = function (date) {
 2156-      return moment(new Date(date)).format('w');
 2157-    };
 2158-
 2159-    Formula.MONTH = function (timestamp) {
 2160-      return new Date(timestamp).getMonth() + 1;
 2161-    };
 2162-
 2163-    Formula.NETWORKDAYS = function (start_date, end_date, holidays) {
 2164-      return Formula.NETWORKDAYSINTL(start_date, end_date, 1, holidays);
 2165-    };
 2166-
 2167-    Formula.NETWORKDAYSINTL = function (start_date, end_date, weekend, holidays) {
 2168-      var weekend_type = (typeof weekend === 'undefined') ? 1 : weekend;
 2169-      var weekend_days = WEEKEND_TYPES[weekend_type];
 2170-      var sd = moment(start_date);
 2171-      var ed = moment(end_date);
 2172-      var net_days = ed.diff(sd, 'days') + 1;
 2173-      var net_work_days = net_days;
 2174-      var cd = sd;
 2175-      var holiday_dates = [];
 2176-      if (typeof holidays !== 'undefined') {
 2177-        for (var i = 0; i < holidays.length; i++) {
 2178-          holiday_dates[i] = moment(new Date(holidays[i])).format('MM-DD-YYYY');
 2179-        }
 2180-      }
 2181-
 2182-      if (!weekend_days.length && !holiday_dates.length) {
 2183-        // No need to loop here.
 2184-        return net_work_days;
 2185-      }
 2186-      var j = 0;
 2187-      while (j < net_days) {
 2188-        if (weekend_days.indexOf(parseInt(cd.format('d'), 10)) >= 0) {
 2189-          net_work_days--;
 2190-        } else if (holiday_dates.indexOf(cd.format('MM-DD-YYYY')) >= 0) {
 2191-          net_work_days--;
 2192-        }
 2193-        cd = cd.add('days', 1);
 2194-        j++;
 2195-      }
 2196-      return net_work_days;
 2197-    };
 2198-
 2199-    Formula.NOW = function () {
 2200-      return new Date();
 2201-    };
 2202-
 2203-    Formula.SECOND = function (timestamp) {
 2204-      return new Date(timestamp).getSeconds();
 2205-    };
 2206-
 2207-    Formula.TIME = function (hour, minute, second) {
 2208-      return (3600 * hour + 60 * minute + second) / 86400;
 2209-    };
 2210-
 2211-    Formula.TIMEVALUE = function (time_text) {
 2212-      var timestamp = new Date(time_text);
 2213-      return (3600 * timestamp.getHours() + 60 * timestamp.getMinutes() + timestamp.getSeconds()) / 86400;
 2214-    };
 2215-
 2216-    Formula.TODAY = Formula.NOW;
 2217-
 2218-    Formula.WEEKDAY = function (date, type) {
 2219-      var week_day = moment(new Date(date)).format('d');
 2220-      var week_type = (typeof type === 'undefined') ? 1 : type;
 2221-      return WEEK_TYPES[week_type][week_day];
 2222-    };
 2223-
 2224-    Formula.WEEKNUM = function (date, type) {
 2225-      var current_date = moment(new Date(date));
 2226-      var january_first = moment(new Date(current_date.year(), 0, 1));
 2227-      var week_type = (typeof type === 'undefined') ? 1 : type;
 2228-      var week_start = WEEK_STARTS[week_type];
 2229-      var first_day = january_first.format('d');
 2230-      var offset = (first_day < week_start) ? week_start - first_day + 1 : first_day - week_start;
 2231-      if (week_type === 21) {
 2232-        return Formula.ISOWEEKNUM(date);
 2233-      } else {
 2234-        return Math.floor(current_date.diff(january_first.subtract('days', offset), 'days') / 7) + 1;
 2235-      }
 2236-    };
 2237-
 2238-    Formula.WORKDAY = function (start_date, days, holidays) {
 2239-      return Formula.WORKDAYINTL(start_date, days, 1, holidays);
 2240-    };
 2241-
 2242-    Formula.WORKDAYINTL = function (start_date, days, weekend, holidays) {
 2243-      var weekend_type = (typeof weekend === 'undefined') ? 1 : weekend;
 2244-      var weekend_days = WEEKEND_TYPES[weekend_type];
 2245-      var sd = moment(new Date(start_date));
 2246-      var cd = sd;
 2247-      var day_of_week = '';
 2248-      var holiday_dates = [];
 2249-      if (typeof holidays !== 'undefined') {
 2250-        for (var i = 0; i < holidays.length; i++) {
 2251-          holiday_dates[i] = moment(new Date(holidays[i])).format('MM-DD-YYYY');
 2252-        }
 2253-      }
 2254-      var j = 0;
 2255-      while (j < days) {
 2256-        cd = cd.add('days', 1);
 2257-        day_of_week = cd.format('d');
 2258-        if (weekend_days.indexOf(parseInt(day_of_week, 10)) < 0 && holiday_dates.indexOf(cd.format('MM-DD-YYYY')) < 0) {
 2259-          j++;
 2260-        }
 2261-      }
 2262-      return cd.toDate();
 2263-    };
 2264-
 2265-    Formula.YEAR = function (date) {
 2266-      return new Date(date).getFullYear();
 2267-    };
 2268-
 2269-    Formula.YEARFRAC = function (start_date, end_date, basis) {
 2270-      // Credits: David A. Wheeler [http://www.dwheeler.com/]
 2271-
 2272-      // Initialize parameters
 2273-      basis = (typeof basis === 'undefined') ? 0 : basis;
 2274-      var sdate = moment(new Date(start_date));
 2275-      var edate = moment(new Date(end_date));
 2276-
 2277-      // Return error if either date is invalid
 2278-      if (!sdate.isValid() || !edate.isValid()) {
 2279-        return '#VALUE!';
 2280-      }
 2281-
 2282-      // Return error if basis is neither 0, 1, 2, 3, or 4
 2283-      if ([0, 1, 2, 3, 4].indexOf(basis) === -1) {
 2284-        return '#NUM!';
 2285-      }
 2286-
 2287-      // Return zero if start_date and end_date are the same
 2288-      if (sdate === edate) {
 2289-        return 0;
 2290-      }
 2291-
 2292-      // Swap dates if start_date is later than end_date
 2293-      if (sdate.diff(edate) > 0) {
 2294-        edate = moment(new Date(start_date));
 2295-        sdate = moment(new Date(end_date));
 2296-      }
 2297-
 2298-      // Lookup years, months, and days
 2299-      var syear = sdate.year();
 2300-      var smonth = sdate.month();
 2301-      var sday = sdate.date();
 2302-      var eyear = edate.year();
 2303-      var emonth = edate.month();
 2304-      var eday = edate.date();
 2305-
 2306-      switch (basis) {
 2307-        case 0:
 2308-          // US (NASD) 30/360
 2309-          // Note: if eday == 31, it stays 31 if sday < 30
 2310-          if (sday === 31 && eday === 31) {
 2311-            sday = 30;
 2312-            eday = 30;
 2313-          } else if (sday === 31) {
 2314-            sday = 30;
 2315-          } else if (sday === 30 && eday === 31) {
 2316-            eday = 30;
 2317-          } else if (smonth === 1 && emonth === 1 && sdate.daysInMonth() === sday && edate.daysInMonth() === eday) {
 2318-            sday = 30;
 2319-            eday = 30;
 2320-          } else if (smonth === 1 && sdate.daysInMonth() === sday) {
 2321-            sday = 30;
 2322-          }
 2323-          return ((eday + emonth * 30 + eyear * 360) - (sday + smonth * 30 + syear * 360)) / 360;
 2324-
 2325-        case 1:
 2326-          // Actual/actual
 2327-          var feb29Between = function (date1, date2) {
 2328-            // Requires year2 == (year1 + 1) or year2 == year1
 2329-            // Returns TRUE if February 29 is between the two dates (date1 may be February 29), with two possibilities:
 2330-            // year1 is a leap year and date1 <= Februay 29 of year1
 2331-            // year2 is a leap year and date2 > Februay 29 of year2
 2332-
 2333-            var mar1year1 = moment(new Date(date1.year(), 2, 1));
 2334-            if (moment([date1.year()]).isLeapYear() && date1.diff(mar1year1) < 0 && date2.diff(mar1year1) >= 0) {
 2335-              return true;
 2336-            }
 2337-            var mar1year2 = moment(new Date(date2.year(), 2, 1));
 2338-            if (moment([date2.year()]).isLeapYear() && date2.diff(mar1year2) >= 0 && date1.diff(mar1year2) < 0) {
 2339-              return true;
 2340-            }
 2341-            return false;
 2342-          };
 2343-          var ylength = 365;
 2344-          if (syear === eyear || ((syear + 1) === eyear) && ((smonth > emonth) || ((smonth === emonth) && (sday >= eday)))) {
 2345-            if (syear === eyear && moment([syear]).isLeapYear()) {
 2346-              ylength = 366;
 2347-            } else if (feb29Between(sdate, edate) || (emonth === 1 && eday === 29)) {
 2348-              ylength = 366;
 2349-            }
 2350-            return edate.diff(sdate, 'days') / ylength;
 2351-          } else {
 2352-            var years = (eyear - syear) + 1;
 2353-            var days = moment(new Date(eyear + 1, 0, 1)).diff(moment(new Date(syear, 0, 1)), 'days');
 2354-            var average = days / years;
 2355-            return edate.diff(sdate, 'days') / average;
 2356-          }
 2357-          break;
 2358-
 2359-        case 2:
 2360-          // Actual/360
 2361-          return edate.diff(sdate, 'days') / 360;
 2362-
 2363-        case 3:
 2364-          // Actual/365
 2365-          return edate.diff(sdate, 'days') / 365;
 2366-
 2367-        case 4:
 2368-          // European 30/360
 2369-          if (sday === 31) {
 2370-            sday = 30;
 2371-          }
 2372-
 2373-          if (eday === 31) {
 2374-            eday = 30;
 2375-          }
 2376-          // Remarkably, do NOT change February 28 or February 29 at ALL
 2377-          return ((eday + emonth * 30 + eyear * 360) - (sday + smonth * 30 + syear * 360)) / 360;
 2378-      }
 2379-    };
 2380-
 2381-    // Engineering functions
 2382-
 2383-    // This function is extracted from the source code of SheetJS/bessel:
 2384-    // https://github.com/SheetJS/bessel/blob/master/bessel.js#L144
 2385-    Formula.BESSELI = (function() {
 2386-      function horner(arr, v) {
 2387-        return arr.reduce(function(z, w) {
 2388-          return v*z + w;
 2389-        }, 0);
 2390-      }
 2391-      var b0_a = [1.0, 3.5156229, 3.0899424, 1.2067492, 0.2659732, 0.360768e-1, 0.45813e-2].reverse();
 2392-      var b0_b = [0.39894228, 0.1328592e-1, 0.225319e-2, -0.157565e-2, 0.916281e-2, -0.2057706e-1, 0.2635537e-1, -0.1647633e-1, 0.392377e-2].reverse();
 2393-      function bessel0(x) {
 2394-        if(x <= 3.75) {
 2395-          return horner(b0_a, x*x/(3.75*3.75));
 2396-        }
 2397-        return Math.exp(Math.abs(x))/Math.sqrt(Math.abs(x))*horner(b0_b, 3.75/Math.abs(x));
 2398-      }
 2399-
 2400-      var b1_a = [0.5, 0.87890594, 0.51498869, 0.15084934, 0.2658733e-1, 0.301532e-2, 0.32411e-3].reverse();
 2401-      var b1_b = [0.39894228, -0.3988024e-1, -0.362018e-2, 0.163801e-2, -0.1031555e-1, 0.2282967e-1, -0.2895312e-1, 0.1787654e-1, -0.420059e-2].reverse();
 2402-      function bessel1(x) {
 2403-        if(x < 3.75) {
 2404-          return x * horner(b1_a, x*x/(3.75*3.75));
 2405-        }
 2406-        return (x < 0 ? -1 : 1) * Math.exp(Math.abs(x))/Math.sqrt(Math.abs(x))*horner(b1_b, 3.75/Math.abs(x));
 2407-      }
 2408-
 2409-      return function besseli(x, n) {
 2410-        n = Math.round(n);
 2411-        if(n === 0) {
 2412-          return bessel0(x);
 2413-        }
 2414-        if(n === 1) {
 2415-          return bessel1(x);
 2416-        }
 2417-        if(n < 0) {
 2418-          throw 'BESSELI Order (' + n + ') must be nonnegative';
 2419-        }
 2420-        if(Math.abs(x) === 0) {
 2421-          return 0;
 2422-        }
 2423-
 2424-        var ret, j, tox = 2 / Math.abs(x), m, bip, bi, bim;
 2425-        m=2*Math.round((n+Math.round(Math.sqrt(40*n)))/2);
 2426-        bip=ret=0.0;
 2427-        bi=1.0;
 2428-        for (j=m;j>0;j--) {
 2429-          bim=j*tox*bi + bip;
 2430-          bip=bi; bi=bim;
 2431-          if (Math.abs(bi) > 1E10) {
 2432-            bi *= 1E-10;
 2433-            bip *= 1E-10;
 2434-            ret *= 1E-10;
 2435-          }
 2436-          if(j === n) {
 2437-            ret = bip;
 2438-          }
 2439-        }
 2440-        ret *= besseli(x, 0) / bi;
 2441-        return x < 0 && (n%2) ? -ret : ret;
 2442-      };
 2443-
 2444-    })();
 2445-
 2446-    // This function is extracted from the source code of SheetJS/bessel:
 2447-    // https://github.com/SheetJS/bessel/blob/master/bessel.js#L25
 2448-    Formula.BESSELJ = (function() {
 2449-      function horner(arr, v) {
 2450-        return arr.reduce(function(z, w) {
 2451-          return v*z + w;
 2452-        }, 0);
 2453-      }
 2454-      var b0_a1a = [57568490574.0,-13362590354.0,651619640.7,-11214424.18,77392.33017,-184.9052456].reverse();
 2455-      var b0_a2a = [57568490411.0,1029532985.0,9494680.718,59272.64853,267.8532712,1.0].reverse();
 2456-      var b0_a1b = [1.0, -0.1098628627e-2, 0.2734510407e-4, -0.2073370639e-5, 0.2093887211e-6].reverse();
 2457-      var b0_a2b = [-0.1562499995e-1, 0.1430488765e-3, -0.6911147651e-5, 0.7621095161e-6, -0.934935152e-7].reverse();
 2458-      var W = 0.636619772; // 2 / Math.PI
 2459-
 2460-      function bessel0(x) {
 2461-        var a, a1, a2, y = x * x, xx = Math.abs(x) - 0.785398164;
 2462-        if(Math.abs(x) < 8) {
 2463-          a1 = horner(b0_a1a, y);
 2464-          a2 = horner(b0_a2a, y);
 2465-          a = a1/a2;
 2466-        }
 2467-        else {
 2468-          y = 64 / y;
 2469-          a1 = horner(b0_a1b, y);
 2470-          a2 = horner(b0_a2b, y);
 2471-          a = Math.sqrt(W/Math.abs(x))*(Math.cos(xx)*a1-Math.sin(xx)*a2*8/Math.abs(x));
 2472-        }
 2473-        return a;
 2474-      }
 2475-      var b1_a1a = [72362614232.0,-7895059235.0,242396853.1,-2972611.439, 15704.48260, -30.16036606].reverse();
 2476-      var b1_a2a = [144725228442.0, 2300535178.0, 18583304.74, 99447.43394, 376.9991397, 1.0].reverse();
 2477-      var b1_a1b = [1.0, 0.183105e-2, -0.3516396496e-4, 0.2457520174e-5, -0.240337019e-6].reverse();
 2478-      var b1_a2b = [0.04687499995, -0.2002690873e-3, 0.8449199096e-5, -0.88228987e-6, 0.105787412e-6].reverse();
 2479-      function bessel1(x) {
 2480-        var a, a1, a2, y = x*x, xx = Math.abs(x) - 2.356194491;
 2481-        if(Math.abs(x)< 8) {
 2482-          a1 = x*horner(b1_a1a, y);
 2483-          a2 = horner(b1_a2a, y);
 2484-          a = a1 / a2;
 2485-        } else {
 2486-          y = 64 / y;
 2487-          a1=horner(b1_a1b, y);
 2488-          a2=horner(b1_a2b, y);
 2489-          a=Math.sqrt(W/Math.abs(x))*(Math.cos(xx)*a1-Math.sin(xx)*a2*8/Math.abs(x));
 2490-          if(x < 0) {
 2491-            a = -a;
 2492-          }
 2493-        }
 2494-        return a;
 2495-      }
 2496-
 2497-      function _bessel_iter(x, n, f0, f1, sign) {
 2498-        if(!sign) {
 2499-          sign = -1;
 2500-        }
 2501-        var tdx = 2 / x, f2;
 2502-        if(n === 0) {
 2503-          return f0;
 2504-        }
 2505-        if(n === 1) {
 2506-          return f1;
 2507-        }
 2508-        for(var o = 1; o !== n; ++o) {
 2509-          f2 = f1 * o * tdx + sign * f0;
 2510-          f0 = f1; f1 = f2;
 2511-        }
 2512-        return f1;
 2513-      }
 2514-
 2515-      return function besselj(x, n) {
 2516-        n = Math.round(n);
 2517-        if(n === 0) {
 2518-          return bessel0(Math.abs(x));
 2519-        }
 2520-        if(n === 1) {
 2521-          return bessel1(Math.abs(x));
 2522-        }
 2523-        if(n < 0) {
 2524-          throw 'BESSELJ: Order (' + n + ') must be nonnegative';
 2525-        }
 2526-        if(Math.abs(x) === 0) {
 2527-          return 0;
 2528-        }
 2529-
 2530-        var ret, j, tox = 2 / Math.abs(x), m, jsum, sum, bjp, bj, bjm;
 2531-        if(Math.abs(x) > n) {
 2532-          ret = _bessel_iter(x, n, bessel0(Math.abs(x)), bessel1(Math.abs(x)),-1);
 2533-        } else {
 2534-          m=2*Math.floor((n+Math.floor(Math.sqrt(40*n)))/2);
 2535-          jsum=0;
 2536-          bjp=ret=sum=0.0;
 2537-          bj=1.0;
 2538-          for (j=m;j>0;j--) {
 2539-            bjm=j*tox*bj-bjp;
 2540-            bjp=bj;
 2541-            bj=bjm;
 2542-            if (Math.abs(bj) > 1E10) {
 2543-              bj *= 1E-10;
 2544-              bjp *= 1E-10;
 2545-              ret *= 1E-10;
 2546-              sum *= 1E-10;
 2547-            }
 2548-            if (jsum) {
 2549-              sum += bj;
 2550-            }
 2551-            jsum=!jsum;
 2552-            if (j === n) {
 2553-              ret=bjp;
 2554-            }
 2555-          }
 2556-          sum=2.0*sum-bj;
 2557-          ret /= sum;
 2558-        }
 2559-        return x < 0 && (n%2) ? -ret : ret;
 2560-      };
 2561-    })();
 2562-
 2563-    // This function is extracted from the source code of SheetJS/bessel:
 2564-    // https://github.com/SheetJS/bessel/blob/master/bessel.js#L186
 2565-    Formula.BESSELK = (function() {
 2566-      function horner(arr, v) {
 2567-        return arr.reduce(function(z, w) {
 2568-          return v*z + w;
 2569-        }, 0);
 2570-      }
 2571-      var b0_a = [-0.57721566, 0.42278420, 0.23069756, 0.3488590e-1, 0.262698e-2, 0.10750e-3, 0.74e-5].reverse();
 2572-      var b0_b = [1.25331414, -0.7832358e-1, 0.2189568e-1, -0.1062446e-1, 0.587872e-2, -0.251540e-2, 0.53208e-3].reverse();
 2573-      function bessel0(x) {
 2574-        if(x <= 2) {
 2575-          return -Math.log(x/2)*Formula.BESSELI(x,0) + horner(b0_a,x*x/4);
 2576-        }
 2577-        return Math.exp(-x)/Math.sqrt(x)*horner(b0_b,2/x);
 2578-      }
 2579-
 2580-      var b1_a = [1.0, 0.15443144, -0.67278579, -0.18156897, -0.1919402e-1, -0.110404e-2, -0.4686e-4].reverse();
 2581-      var b1_b = [1.25331414, 0.23498619, -0.3655620e-1, 0.1504268e-1, -0.780353e-2, 0.325614e-2, -0.68245e-3].reverse();
 2582-      function bessel1(x) {
 2583-        if(x <= 2) {
 2584-          return Math.log(x/2)*Formula.BESSELI(x,1) + (1/x)*horner(b1_a,x*x/4);
 2585-        }
 2586-        return Math.exp(-x)/Math.sqrt(x)*horner(b1_b,2/x);
 2587-      }
 2588-
 2589-      function _bessel_iter(x, n, f0, f1, sign) {
 2590-        if(!sign) {
 2591-          sign = -1;
 2592-        }
 2593-        var tdx = 2 / x, f2;
 2594-        if(n === 0) {
 2595-          return f0;
 2596-        }
 2597-        if(n === 1) {
 2598-          return f1;
 2599-        }
 2600-        for(var o = 1; o !== n; ++o) {
 2601-          f2 = f1 * o * tdx + sign * f0;
 2602-          f0 = f1; f1 = f2;
 2603-        }
 2604-        return f1;
 2605-      }
 2606-
 2607-      function _bessel_wrap(bessel0, bessel1, name, nonzero, sign) {
 2608-        return function bessel(x,n) {
 2609-          if(n === 0) {
 2610-            return bessel0(x);
 2611-          }
 2612-          if(n === 1) {
 2613-            return bessel1(x);
 2614-          }
 2615-          if(n < 0) {
 2616-            throw name + ': Order (' + n + ') must be nonnegative';
 2617-          }
 2618-          if(nonzero === 1 && x === 0) {
 2619-            throw name + ': Undefined when x == 0';
 2620-          }
 2621-          if(nonzero === 2 && x <= 0) {
 2622-            throw name + ': Undefined when x <= 0';
 2623-          }
 2624-          var b0 = bessel0(x), b1 = bessel1(x);
 2625-          return _bessel_iter(x, n, b0, b1, sign);
 2626-        };
 2627-      }
 2628-
 2629-      return _bessel_wrap(bessel0, bessel1, 'BESSELK', 2, 1);
 2630-    })();
 2631-
 2632-    // This function is extracted from the source code of SheetJS/bessel:
 2633-    // https://github.com/SheetJS/bessel/blob/master/bessel.js#L101
 2634-    Formula.BESSELY = (function() {
 2635-      function horner(arr, v) {
 2636-        return arr.reduce(function(z, w) {
 2637-          return v*z + w;
 2638-        }, 0);
 2639-      }
 2640-      var b0_a1a = [-2957821389.0, 7062834065.0, -512359803.6, 10879881.29, -86327.92757, 228.4622733].reverse();
 2641-      var b0_a2a = [40076544269.0, 745249964.8, 7189466.438, 47447.26470, 226.1030244, 1.0].reverse();
 2642-      var b0_a1b = [1.0, -0.1098628627e-2, 0.2734510407e-4, -0.2073370639e-5, 0.2093887211e-6].reverse();
 2643-      var b0_a2b = [-0.1562499995e-1, 0.1430488765e-3, -0.6911147651e-5, 0.7621095161e-6, -0.934945152e-7].reverse();
 2644-
 2645-      var W = 0.636619772;
 2646-      function bessel0(x) {
 2647-        var a, a1, a2, y = x * x, xx = x - 0.785398164;
 2648-        if(x < 8) {
 2649-          a1 = horner(b0_a1a, y);
 2650-          a2 = horner(b0_a2a, y);
 2651-          a = a1/a2 + W * Formula.BESSELJ(x,0) * Math.log(x);
 2652-        } else {
 2653-          y = 64 / y;
 2654-          a1 = horner(b0_a1b, y);
 2655-          a2 = horner(b0_a2b, y);
 2656-          a = Math.sqrt(W/x)*(Math.sin(xx)*a1+Math.cos(xx)*a2*8/x);
 2657-        }
 2658-        return a;
 2659-      }
 2660-
 2661-      var b1_a1a = [-0.4900604943e13, 0.1275274390e13, -0.5153438139e11, 0.7349264551e9, -0.4237922726e7, 0.8511937935e4].reverse();
 2662-      var b1_a2a = [0.2499580570e14, 0.4244419664e12, 0.3733650367e10, 0.2245904002e8, 0.1020426050e6, 0.3549632885e3, 1].reverse();
 2663-      var b1_a1b = [1.0, 0.183105e-2, -0.3516396496e-4, 0.2457520174e-5, -0.240337019e-6].reverse();
 2664-      var b1_a2b = [0.04687499995, -0.2002690873e-3, 0.8449199096e-5, -0.88228987e-6, 0.105787412e-6].reverse();
 2665-      function bessel1(x) {
 2666-        var a, a1, a2, y = x*x, xx = x - 2.356194491;
 2667-        if(x < 8) {
 2668-          a1 = x*horner(b1_a1a, y);
 2669-          a2 = horner(b1_a2a, y);
 2670-          a = a1/a2 + W * (Formula.BESSELJ(x,1) * Math.log(x) - 1 / x);
 2671-        } else {
 2672-          y = 64 / y;
 2673-          a1=horner(b1_a1b, y);
 2674-          a2=horner(b1_a2b, y);
 2675-          a=Math.sqrt(W/x)*(Math.sin(xx)*a1+Math.cos(xx)*a2*8/x);
 2676-        }
 2677-        return a;
 2678-      }
 2679-
 2680-      function _bessel_iter(x, n, f0, f1, sign) {
 2681-        if(!sign) {
 2682-          sign = -1;
 2683-        }
 2684-        var tdx = 2 / x, f2;
 2685-        if(n === 0) {
 2686-          return f0;
 2687-        }
 2688-        if(n === 1) {
 2689-          return f1;
 2690-        }
 2691-        for(var o = 1; o !== n; ++o) {
 2692-          f2 = f1 * o * tdx + sign * f0;
 2693-          f0 = f1; f1 = f2;
 2694-        }
 2695-        return f1;
 2696-      }
 2697-
 2698-      function _bessel_wrap(bessel0, bessel1, name, nonzero, sign) {
 2699-        return function bessel(x,n) {
 2700-          if(n === 0) {
 2701-            return bessel0(x);
 2702-          }
 2703-          if(n === 1) {
 2704-            return bessel1(x);
 2705-          }
 2706-          if(n < 0) {
 2707-            throw name + ': Order (' + n + ') must be nonnegative';
 2708-          }
 2709-          if(nonzero === 1 && x === 0) {
 2710-            throw name + ': Undefined when x == 0';
 2711-          }
 2712-          if(nonzero === 2 && x <= 0) {
 2713-            throw name + ': Undefined when x <= 0';
 2714-          }
 2715-          var b0 = bessel0(x), b1 = bessel1(x);
 2716-          return _bessel_iter(x, n, b0, b1, sign);
 2717-        };
 2718-      }
 2719-
 2720-      return _bessel_wrap(bessel0, bessel1, 'BESSELY', 1, -1);
 2721-    })();
 2722-
 2723-    Formula.VALIDBIN = function (number) {
 2724-      return (/^[01]{1,10}$/).test(number);
 2725-    };
 2726-
 2727-    Formula.BIN2DEC = function (number) {
 2728-      // Return error if number is not binary or contains more than 10 characters (10 digits)
 2729-      if (!Formula.VALIDBIN(number)) {
 2730-        return '#NUM!';
 2731-      }
 2732-
 2733-      // Convert binary number to decimal
 2734-      var result = parseInt(number, 2);
 2735-
 2736-      // Handle negative numbers
 2737-      var stringified = number.toString();
 2738-      if (stringified.length === 10 && stringified.substring(0, 1) === '1') {
 2739-        return parseInt(stringified.substring(1), 2) - 512;
 2740-      } else {
 2741-        return result;
 2742-      }
 2743-    };
 2744-
 2745-    Formula.BIN2HEX = function (number, places) {
 2746-      // Return error if number is not binary or contains more than 10 characters (10 digits)
 2747-      if (!Formula.VALIDBIN(number)) {
 2748-        return '#NUM!';
 2749-      }
 2750-
 2751-      // Ignore places and return a 10-character hexadecimal number if number is negative
 2752-      var stringified = number.toString();
 2753-      if (stringified.length === 10 && stringified.substring(0, 1) === '1') {
 2754-        return (1099511627264 + parseInt(stringified.substring(1), 2)).toString(16);
 2755-      }
 2756-
 2757-      // Convert binary number to hexadecimal
 2758-      var result = parseInt(number, 2).toString(16);
 2759-
 2760-      // Return hexadecimal number using the minimum number of characters necessary if places is undefined
 2761-      if (typeof places === 'undefined') {
 2762-        return result;
 2763-      } else {
 2764-        // Return error if places is nonnumeric
 2765-        if (isNaN(places)) {
 2766-          return '#VALUE!';
 2767-        }
 2768-
 2769-        // Return error if places is negative
 2770-        if (places < 0) {
 2771-          return '#NUM!';
 2772-        }
 2773-
 2774-        // Truncate places in case it is not an integer
 2775-        places = Math.floor(places);
 2776-
 2777-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 2778-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 2779-      }
 2780-    };
 2781-
 2782-    Formula.BIN2OCT = function (number, places) {
 2783-      // Return error if number is not binary or contains more than 10 characters (10 digits)
 2784-      if (!Formula.VALIDBIN(number)) {
 2785-        return '#NUM!';
 2786-      }
 2787-
 2788-      // Ignore places and return a 10-character octal number if number is negative
 2789-      var stringified = number.toString();
 2790-      if (stringified.length === 10 && stringified.substring(0, 1) === '1') {
 2791-        return (1073741312 + parseInt(stringified.substring(1), 2)).toString(8);
 2792-      }
 2793-
 2794-      // Convert binary number to octal
 2795-      var result = parseInt(number, 2).toString(8);
 2796-
 2797-      // Return octal number using the minimum number of characters necessary if places is undefined
 2798-      if (typeof places === 'undefined') {
 2799-        return result;
 2800-      } else {
 2801-        // Return error if places is nonnumeric
 2802-        if (isNaN(places)) {
 2803-          return '#VALUE!';
 2804-        }
 2805-
 2806-        // Return error if places is negative
 2807-        if (places < 0) {
 2808-          return '#NUM!';
 2809-        }
 2810-
 2811-        // Truncate places in case it is not an integer
 2812-        places = Math.floor(places);
 2813-
 2814-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 2815-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 2816-      }
 2817-    };
 2818-
 2819-    Formula.BITAND = function (number1, number2) {
 2820-      // Return error if either number is a non-numeric value
 2821-      if (isNaN(number1) || isNaN(number2)) {
 2822-        return '#VALUE!';
 2823-      }
 2824-
 2825-      // Return error if either number is less than 0
 2826-      if (number1 < 0 || number2 < 0) {
 2827-        return '#NUM!';
 2828-      }
 2829-
 2830-      // Return error if either number is a non-integer
 2831-      if (Math.floor(number1) !== number1 || Math.floor(number2) !== number2) {
 2832-        return '#NUM!';
 2833-      }
 2834-
 2835-      // Return error if either number is greater than (2^48)-1
 2836-      if (number1 > 281474976710655 || number2 > 281474976710655) {
 2837-        return '#NUM!';
 2838-      }
 2839-
 2840-      // Return bitwise AND of two numbers
 2841-      return number1 & number2;
 2842-    };
 2843-
 2844-    Formula.BITLSHIFT = function (number, shift) {
 2845-      // Return error if either number is a non-numeric value
 2846-      if (isNaN(number) || isNaN(shift)) {
 2847-        return '#VALUE!';
 2848-      }
 2849-
 2850-      // Return error if number is less than 0
 2851-      if (number < 0) {
 2852-        return '#NUM!';
 2853-      }
 2854-
 2855-      // Return error if number is a non-integer
 2856-      if (Math.floor(number) !== number) {
 2857-        return '#NUM!';
 2858-      }
 2859-
 2860-      // Return error if number is greater than (2^48)-1
 2861-      if (number > 281474976710655) {
 2862-        return '#NUM!';
 2863-      }
 2864-
 2865-      // Return error if the absolute value of shift is greater than 53
 2866-      if (Math.abs(shift) > 53) {
 2867-        return '#NUM!';
 2868-      }
 2869-
 2870-      // Return number shifted by shift bits to the left or to the right if shift is negative
 2871-      return (shift >= 0 ) ? number << shift : number >> -shift;
 2872-    };
 2873-
 2874-    Formula.BITOR = function (number1, number2) {
 2875-      // Return error if either number is a non-numeric value
 2876-      if (isNaN(number1) || isNaN(number2)) {
 2877-        return '#VALUE!';
 2878-      }
 2879-
 2880-      // Return error if either number is less than 0
 2881-      if (number1 < 0 || number2 < 0) {
 2882-        return '#NUM!';
 2883-      }
 2884-
 2885-      // Return error if either number is a non-integer
 2886-      if (Math.floor(number1) !== number1 || Math.floor(number2) !== number2) {
 2887-        return '#NUM!';
 2888-      }
 2889-
 2890-      // Return error if either number is greater than (2^48)-1
 2891-      if (number1 > 281474976710655 || number2 > 281474976710655) {
 2892-        return '#NUM!';
 2893-      }
 2894-
 2895-      // Return bitwise OR of two numbers
 2896-      return number1 | number2;
 2897-    };
 2898-
 2899-    Formula.BITRSHIFT = function (number, shift) {
 2900-      // Return error if either number is a non-numeric value
 2901-      if (isNaN(number) || isNaN(shift)) {
 2902-        return '#VALUE!';
 2903-      }
 2904-
 2905-      // Return error if number is less than 0
 2906-      if (number < 0) {
 2907-        return '#NUM!';
 2908-      }
 2909-
 2910-      // Return error if number is a non-integer
 2911-      if (Math.floor(number) !== number) {
 2912-        return '#NUM!';
 2913-      }
 2914-
 2915-      // Return error if number is greater than (2^48)-1
 2916-      if (number > 281474976710655) {
 2917-        return '#NUM!';
 2918-      }
 2919-
 2920-      // Return error if the absolute value of shift is greater than 53
 2921-      if (Math.abs(shift) > 53) {
 2922-        return '#NUM!';
 2923-      }
 2924-
 2925-      // Return number shifted by shift bits to the right or to the left if shift is negative
 2926-      return (shift >= 0 ) ? number >> shift : number << -shift;
 2927-    };
 2928-
 2929-    Formula.BITXOR = function (number1, number2) {
 2930-      // Return error if either number is a non-numeric value
 2931-      if (isNaN(number1) || isNaN(number2)) {
 2932-        return '#VALUE!';
 2933-      }
 2934-
 2935-      // Return error if either number is less than 0
 2936-      if (number1 < 0 || number2 < 0) {
 2937-        return '#NUM!';
 2938-      }
 2939-
 2940-      // Return error if either number is a non-integer
 2941-      if (Math.floor(number1) !== number1 || Math.floor(number2) !== number2) {
 2942-        return '#NUM!';
 2943-      }
 2944-
 2945-      // Return error if either number is greater than (2^48)-1
 2946-      if (number1 > 281474976710655 || number2 > 281474976710655) {
 2947-        return '#NUM!';
 2948-      }
 2949-
 2950-      // Return bitwise XOR of two numbers
 2951-      return number1 ^ number2;
 2952-    };
 2953-
 2954-    Formula.COMPLEX = function (real, imaginary, suffix) {
 2955-      // Return error if either number is a non-numeric value
 2956-      if (isNaN(real) || isNaN(imaginary)) {
 2957-        return '#VALUE!';
 2958-      }
 2959-
 2960-      // Set suffix
 2961-      suffix = (typeof suffix === 'undefined') ? 'i' : suffix;
 2962-
 2963-      // Return error if suffix is neither "i" nor "j"
 2964-      if (suffix !== 'i' && suffix !== 'j') {
 2965-        return '#VALUE!';
 2966-      }
 2967-
 2968-      // Return complex number
 2969-      if (real === 0 && imaginary === 0) {
 2970-        return 0;
 2971-      } else if (real === 0) {
 2972-        return (imaginary === 1) ? suffix : imaginary.toString() + suffix;
 2973-      } else if (imaginary === 0) {
 2974-        return real.toString();
 2975-      } else {
 2976-        var sign = (imaginary > 0) ? '+' : '';
 2977-        return real.toString() + sign + ((imaginary === 1) ? suffix : imaginary.toString() + suffix);
 2978-      }
 2979-    };
 2980-
 2981-    Formula.CONVERT = function (number, from_unit, to_unit) {
 2982-      // Return error if number is a non-numeric value
 2983-      if (isNaN(number)) {
 2984-        return '#VALUE!';
 2985-      }
 2986-
 2987-      // List of units supported by CONVERT and units defined by the International System of Units
 2988-      // [Name, Symbol, Alternate symbols, Quantity, ISU, CONVERT, Conversion ratio]
 2989-      var units = [
 2990-        ["a.u. of action", "?", null, "action", false, false, 1.05457168181818e-34],
 2991-        ["a.u. of charge", "e", null, "electric_charge", false, false, 1.60217653141414e-19],
 2992-        ["a.u. of energy", "Eh", null, "energy", false, false, 4.35974417757576e-18],
 2993-        ["a.u. of length", "a?", null, "length", false, false, 5.29177210818182e-11],
 2994-        ["a.u. of mass", "m?", null, "mass", false, false, 9.10938261616162e-31],
 2995-        ["a.u. of time", "?/Eh", null, "time", false, false, 2.41888432650516e-17],
 2996-        ["admiralty knot", "admkn", null, "speed", false, true, 0.514773333],
 2997-        ["ampere", "A", null, "electric_current", true, false, 1],
 2998-        ["ampere per meter", "A/m", null, "magnetic_field_intensity", true, false, 1],
 2999-        ["ångström", "Å", ["ang"], "length", false, true, 1e-10],
 3000-        ["are", "ar", null, "area", false, true, 100],
 3001-        ["astronomical unit", "ua", null, "length", false, false, 1.49597870691667e-11],
 3002-        ["bar", "bar", null, "pressure", false, false, 100000],
 3003-        ["barn", "b", null, "area", false, false, 1e-28],
 3004-        ["becquerel", "Bq", null, "radioactivity", true, false, 1],
 3005-        ["bit", "bit", ["b"], "information", false, true, 1],
 3006-        ["btu", "BTU", ["btu"], "energy", false, true, 1055.05585262],
 3007-        ["byte", "byte", null, "information", false, true, 8],
 3008-        ["candela", "cd", null, "luminous_intensity", true, false, 1],
 3009-        ["candela per square metre", "cd/m?", null, "luminance", true, false, 1],
 3010-        ["coulomb", "C", null, "electric_charge", true, false, 1],
 3011-        ["cubic ångström", "ang3", ["ang^3"], "volume", false, true, 1e-30],
 3012-        ["cubic foot", "ft3", ["ft^3"], "volume", false, true, 0.028316846592],
 3013-        ["cubic inch", "in3", ["in^3"], "volume", false, true, 0.000016387064],
 3014-        ["cubic light-year", "ly3", ["ly^3"], "volume", false, true, 8.46786664623715e-47],
 3015-        ["cubic metre", "m?", null, "volume", true, true, 1],
 3016-        ["cubic mile", "mi3", ["mi^3"], "volume", false, true, 4168181825.44058],
 3017-        ["cubic nautical mile", "Nmi3", ["Nmi^3"], "volume", false, true, 6352182208],
 3018-        ["cubic Pica", "Pica3", ["Picapt3", "Pica^3", "Picapt^3"], "volume", false, true, 7.58660370370369e-8],
 3019-        ["cubic yard", "yd3", ["yd^3"], "volume", false, true, 0.764554857984],
 3020-        ["cup", "cup", null, "volume", false, true, 0.0002365882365],
 3021-        ["dalton", "Da", ["u"], "mass", false, false, 1.66053886282828e-27],
 3022-        ["day", "d", ["day"], "time", false, true, 86400],
 3023-        ["degree", "°", null, "angle", false, false, 0.0174532925199433],
 3024-        ["degrees Rankine", "Rank", null, "temperature", false, true, 0.555555555555556],
 3025-        ["dyne", "dyn", ["dy"], "force", false, true, 0.00001],
 3026-        ["electronvolt", "eV", ["ev"], "energy", false, true, 1.60217656514141],
 3027-        ["ell", "ell", null, "length", false, true, 1.143],
 3028-        ["erg", "erg", ["e"], "energy", false, true, 1e-7],
 3029-        ["farad", "F", null, "electric_capacitance", true, false, 1],
 3030-        ["fluid ounce", "oz", null, "volume", false, true, 0.0000295735295625],
 3031-        ["foot", "ft", null, "length", false, true, 0.3048],
 3032-        ["foot-pound", "flb", null, "energy", false, true, 1.3558179483314],
 3033-        ["gal", "Gal", null, "acceleration", false, false, 0.01],
 3034-        ["gallon", "gal", null, "volume", false, true, 0.003785411784],
 3035-        ["gauss", "G", ["ga"], "magnetic_flux_density", false, true, 1],
 3036-        ["grain", "grain", null, "mass", false, true, 0.0000647989],
 3037-        ["gram", "g", null, "mass", false, true, 0.001],
 3038-        ["gray", "Gy", null, "absorbed_dose", true, false, 1],
 3039-        ["gross registered ton", "GRT", ["regton"], "volume", false, true, 2.8316846592],
 3040-        ["hectare", "ha", null, "area", false, true, 10000],
 3041-        ["henry", "H", null, "inductance", true, false, 1],
 3042-        ["hertz", "Hz", null, "frequency", true, false, 1],
 3043-        ["horsepower", "HP", ["h"], "power", false, true, 745.69987158227],
 3044-        ["horsepower-hour", "HPh", ["hh", "hph"], "energy", false, true, 2684519.538],
 3045-        ["hour", "h", ["hr"], "time", false, true, 3600],
 3046-        ["imperial gallon (U.K.)", "uk_gal", null, "volume", false, true, 0.00454609],
 3047-        ["imperial hundredweight", "lcwt", ["uk_cwt", "hweight"], "mass", false, true, 50.802345],
 3048-        ["imperial quart (U.K)", "uk_qt", null, "volume", false, true, 0.0011365225],
 3049-        ["imperial ton", "brton", ["uk_ton", "LTON"], "mass", false, true, 1016.046909],
 3050-        ["inch", "in", null, "length", false, true, 0.0254],
 3051-        ["international acre", "uk_acre", null, "area", false, true, 4046.8564224],
 3052-        ["IT calorie", "cal", null, "energy", false, true, 4.1868],
 3053-        ["joule", "J", null, "energy", true, true, 1],
 3054-        ["katal", "kat", null, "catalytic_activity", true, false, 1],
 3055-        ["kelvin", "K", ["kel"], "temperature", true, true, 1],
 3056-        ["kilogram", "kg", null, "mass", true, true, 1],
 3057-        ["knot", "kn", null, "speed", false, true, 0.514444444444444],
 3058-        ["light-year", "ly", null, "length", false, true, 9460730472580800],
 3059-        ["litre", "L", ["l", "lt"], "volume", false, true, 0.001],
 3060-        ["lumen", "lm", null, "luminous_flux", true, false, 1],
 3061-        ["lux", "lx", null, "illuminance", true, false, 1],
 3062-        ["maxwell", "Mx", null, "magnetic_flux", false, false, 1e-18],
 3063-        ["measurement ton", "MTON", null, "volume", false, true, 1.13267386368],
 3064-        ["meter per hour", "m/h", ["m/hr"], "speed", false, true, 0.00027777777777778],
 3065-        ["meter per second", "m/s", ["m/sec"], "speed", true, true, 1],
 3066-        ["meter per second squared", "m?s??", null, "acceleration", true, false, 1],
 3067-        ["parsec", "pc", ["parsec"], "length", false, true, 30856775814671900],
 3068-        ["meter squared per second", "m?/s", null, "kinematic_viscosity", true, false, 1],
 3069-        ["metre", "m", null, "length", true, true, 1],
 3070-        ["miles per hour", "mph", null, "speed", false, true, 0.44704],
 3071-        ["millimetre of mercury", "mmHg", null, "pressure", false, false, 133.322],
 3072-        ["minute", "?", null, "angle", false, false, 0.000290888208665722],
 3073-        ["minute", "min", ["mn"], "time", false, true, 60],
 3074-        ["modern teaspoon", "tspm", null, "volume", false, true, 0.000005],
 3075-        ["mole", "mol", null, "amount_of_substance", true, false, 1],
 3076-        ["morgen", "Morgen", null, "area", false, true, 2500],
 3077-        ["n.u. of action", "?", null, "action", false, false, 1.05457168181818e-34],
 3078-        ["n.u. of mass", "m?", null, "mass", false, false, 9.10938261616162e-31],
 3079-        ["n.u. of speed", "c?", null, "speed", false, false, 299792458],
 3080-        ["n.u. of time", "?/(me?c??)", null, "time", false, false, 1.28808866778687e-21],
 3081-        ["nautical mile", "M", ["Nmi"], "length", false, true, 1852],
 3082-        ["newton", "N", null, "force", true, true, 1],
 3083-        ["œrsted", "Oe ", null, "magnetic_field_intensity", false, false, 79.5774715459477],
 3084-        ["ohm", "Ω", null, "electric_resistance", true, false, 1],
 3085-        ["ounce mass", "ozm", null, "mass", false, true, 0.028349523125],
 3086-        ["pascal", "Pa", null, "pressure", true, false, 1],
 3087-        ["pascal second", "Pa?s", null, "dynamic_viscosity", true, false, 1],
 3088-        ["pferdestärke", "PS", null, "power", false, true, 735.49875],
 3089-        ["phot", "ph", null, "illuminance", false, false, 0.0001],
 3090-        ["pica (1/6 inch)", "pica", null, "length", false, true, 0.00035277777777778],
 3091-        ["pica (1/72 inch)", "Pica", ["Picapt"], "length", false, true, 0.00423333333333333],
 3092-        ["poise", "P", null, "dynamic_viscosity", false, false, 0.1],
 3093-        ["pond", "pond", null, "force", false, true, 0.00980665],
 3094-        ["pound force", "lbf", null, "force", false, true, 4.4482216152605],
 3095-        ["pound mass", "lbm", null, "mass", false, true, 0.45359237],
 3096-        ["quart", "qt", null, "volume", false, true, 0.000946352946],
 3097-        ["radian", "rad", null, "angle", true, false, 1],
 3098-        ["second", "?", null, "angle", false, false, 0.00000484813681109536],
 3099-        ["second", "s", ["sec"], "time", true, true, 1],
 3100-        ["short hundredweight", "cwt", ["shweight"], "mass", false, true, 45.359237],
 3101-        ["siemens", "S", null, "electrical_conductance", true, false, 1],
 3102-        ["sievert", "Sv", null, "equivalent_dose", true, false, 1],
 3103-        ["slug", "sg", null, "mass", false, true, 14.59390294],
 3104-        ["square ångström", "ang2", ["ang^2"], "area", false, true, 1e-20],
 3105-        ["square foot", "ft2", ["ft^2"], "area", false, true, 0.09290304],
 3106-        ["square inch", "in2", ["in^2"], "area", false, true, 0.00064516],
 3107-        ["square light-year", "ly2", ["ly^2"], "area", false, true, 8.95054210748189e+31],
 3108-        ["square meter", "m?", null, "area", true, true, 1],
 3109-        ["square mile", "mi2", ["mi^2"], "area", false, true, 2589988.110336],
 3110-        ["square nautical mile", "Nmi2", ["Nmi^2"], "area", false, true, 3429904],
 3111-        ["square Pica", "Pica2", ["Picapt2", "Pica^2", "Picapt^2"], "area", false, true, 0.00001792111111111],
 3112-        ["square yard", "yd2", ["yd^2"], "area", false, true, 0.83612736],
 3113-        ["statute mile", "mi", null, "length", false, true, 1609.344],
 3114-        ["steradian", "sr", null, "solid_angle", true, false, 1],
 3115-        ["stilb", "sb", null, "luminance", false, false, 0.0001],
 3116-        ["stokes", "St", null, "kinematic_viscosity", false, false, 0.0001],
 3117-        ["stone", "stone", null, "mass", false, true, 6.35029318],
 3118-        ["tablespoon", "tbs", null, "volume", false, true, 0.0000147868],
 3119-        ["teaspoon", "tsp", null, "volume", false, true, 0.00000492892],
 3120-        ["tesla", "T", null, "magnetic_flux_density", true, true, 1],
 3121-        ["thermodynamic calorie", "c", null, "energy", false, true, 4.184],
 3122-        ["ton", "ton", null, "mass", false, true, 907.18474],
 3123-        ["tonne", "t", null, "mass", false, false, 1000],
 3124-        ["U.K. pint", "uk_pt", null, "volume", false, true, 0.00056826125],
 3125-        ["U.S. bushel", "bushel", null, "volume", false, true, 0.03523907],
 3126-        ["U.S. oil barrel", "barrel", null, "volume", false, true, 0.158987295],
 3127-        ["U.S. pint", "pt", ["us_pt"], "volume", false, true, 0.000473176473],
 3128-        ["U.S. survey mile", "survey_mi", null, "length", false, true, 1609.347219],
 3129-        ["U.S. survey/statute acre", "us_acre", null, "area", false, true, 4046.87261],
 3130-        ["volt", "V", null, "voltage", true, false, 1],
 3131-        ["watt", "W", null, "power", true, true, 1],
 3132-        ["watt-hour", "Wh", ["wh"], "energy", false, true, 3600],
 3133-        ["weber", "Wb", null, "magnetic_flux", true, false, 1],
 3134-        ["yard", "yd", null, "length", false, true, 0.9144],
 3135-        ["year", "yr", null, "time", false, true, 31557600]
 3136-      ];
 3137-
 3138-      // Binary prefixes
 3139-      // [Name, Prefix power of 2 value, Previx value, Abbreviation, Derived from]
 3140-      var binary_prefixes = {
 3141-        Yi: ["yobi", 80, 1208925819614629174706176, "Yi", "yotta"],
 3142-        Zi: ["zebi", 70, 1180591620717411303424, "Zi", "zetta"],
 3143-        Ei: ["exbi", 60, 1152921504606846976, "Ei", "exa"],
 3144-        Pi: ["pebi", 50, 1125899906842624, "Pi", "peta"],
 3145-        Ti: ["tebi", 40, 1099511627776, "Ti", "tera"],
 3146-        Gi: ["gibi", 30, 1073741824, "Gi", "giga"],
 3147-        Mi: ["mebi", 20, 1048576, "Mi", "mega"],
 3148-        ki: ["kibi", 10, 1024, "ki", "kilo"]
 3149-      };
 3150-
 3151-      // Unit prefixes
 3152-      // [Name, Multiplier, Abbreviation]
 3153-      var unit_prefixes = {
 3154-        Y: ["yotta", 1e+24, "Y"],
 3155-        Z: ["zetta", 1e+21, "Z"],
 3156-        E: ["exa", 1e+18, "E"],
 3157-        P: ["peta", 1e+15, "P"],
 3158-        T: ["tera", 1e+12, "T"],
 3159-        G: ["giga", 1e+09, "G"],
 3160-        M: ["mega", 1e+06, "M"],
 3161-        k: ["kilo", 1e+03, "k"],
 3162-        h: ["hecto", 1e+02, "h"],
 3163-        e: ["dekao", 1e+01, "e"],
 3164-        d: ["deci", 1e-01, "d"],
 3165-        c: ["centi", 1e-02, "c"],
 3166-        m: ["milli", 1e-03, "m"],
 3167-        u: ["micro", 1e-06, "u"],
 3168-        n: ["nano", 1e-09, "n"],
 3169-        p: ["pico", 1e-12, "p"],
 3170-        f: ["femto", 1e-15, "f"],
 3171-        a: ["atto", 1e-18, "a"],
 3172-        z: ["zepto", 1e-21, "z"],
 3173-        y: ["yocto", 1e-24, "y"]
 3174-      };
 3175-
 3176-      // Initialize units and multipliers
 3177-      var from = null;
 3178-      var to = null;
 3179-      var base_from_unit = from_unit;
 3180-      var base_to_unit = to_unit;
 3181-      var from_multiplier = 1;
 3182-      var to_multiplier = 1;
 3183-      var alt;
 3184-
 3185-      // Lookup from and to units
 3186-      for (var i = 0; i < units.length; i++) {
 3187-        alt = (units[i][2] === null) ? [] : units[i][2];
 3188-        if (units[i][1] === base_from_unit || alt.indexOf(base_from_unit) >= 0) {
 3189-          from = units[i];
 3190-        }
 3191-        if (units[i][1] === base_to_unit || alt.indexOf(base_to_unit) >= 0) {
 3192-          to = units[i];
 3193-        }
 3194-      }
 3195-
 3196-      // Lookup from prefix
 3197-      if (from === null) {
 3198-        var from_binary_prefix = binary_prefixes[from_unit.substring(0, 2)];
 3199-        var from_unit_prefix = unit_prefixes[from_unit.substring(0, 1)];
 3200-
 3201-        // Handle dekao unit prefix (only unit prefix with two characters)
 3202-        if (from_unit.substring(0, 2) === 'da') {
 3203-          from_unit_prefix = ["dekao", 1e+01, "da"];
 3204-        }
 3205-
 3206-        // Handle binary prefixes first (so that 'Yi' is processed before 'Y')
 3207-        if (from_binary_prefix) {
 3208-          from_multiplier = from_binary_prefix[2];
 3209-          base_from_unit = from_unit.substring(2);
 3210-        } else if (from_unit_prefix) {
 3211-          from_multiplier = from_unit_prefix[1];
 3212-          base_from_unit = from_unit.substring(from_unit_prefix[2].length);
 3213-        }
 3214-
 3215-        // Lookup from unit
 3216-        for (var j = 0; j < units.length; j++) {
 3217-          alt = (units[j][2] === null) ? [] : units[j][2];
 3218-          if (units[j][1] === base_from_unit || alt.indexOf(base_from_unit) >= 0) {
 3219-            from = units[j];
 3220-          }
 3221-        }
 3222-      }
 3223-
 3224-      // Lookup to prefix
 3225-      if (to === null) {
 3226-        var to_binary_prefix = binary_prefixes[to_unit.substring(0, 2)];
 3227-        var to_unit_prefix = unit_prefixes[to_unit.substring(0, 1)];
 3228-
 3229-        // Handle dekao unit prefix (only unit prefix with two characters)
 3230-        if (to_unit.substring(0, 2) === 'da') {
 3231-          to_unit_prefix = ["dekao", 1e+01, "da"];
 3232-        }
 3233-
 3234-        // Handle binary prefixes first (so that 'Yi' is processed before 'Y')
 3235-        if (to_binary_prefix) {
 3236-          to_multiplier = to_binary_prefix[2];
 3237-          base_to_unit = to_unit.substring(2);
 3238-        } else if (to_unit_prefix) {
 3239-          to_multiplier = to_unit_prefix[1];
 3240-          base_to_unit = to_unit.substring(to_unit_prefix[2].length);
 3241-        }
 3242-
 3243-        // Lookup to unit
 3244-        for (var k = 0; k < units.length; k++) {
 3245-          alt = (units[k][2] === null) ? [] : units[k][2];
 3246-          if (units[k][1] === base_to_unit || alt.indexOf(base_to_unit) >= 0) {
 3247-            to = units[k];
 3248-          }
 3249-        }
 3250-      }
 3251-
 3252-      // Return error if a unit does not exist
 3253-      if (from === null || to === null) {
 3254-        return '#N/A';
 3255-      }
 3256-
 3257-      // Return error if units represent different quantities
 3258-      if (from[3] !== to[3]) {
 3259-        return '#N/A';
 3260-      }
 3261-
 3262-      // Return converted number
 3263-      return number * from[6] * from_multiplier / (to[6] * to_multiplier);
 3264-    };
 3265-
 3266-    Formula.DEC2BIN = function (number, places) {
 3267-      // Return error if number is not a number
 3268-      if (isNaN(number)) {
 3269-        return '#VALUE!';
 3270-      }
 3271-
 3272-      // Return error if number is not decimal, is lower than -512, or is greater than 511
 3273-      if (!/^-?[0-9]{1,3}$/.test(number) || number < -512 || number > 511) {
 3274-        return '#NUM!';
 3275-      }
 3276-
 3277-      // Ignore places and return a 10-character binary number if number is negative
 3278-      if (number < 0) {
 3279-        return '1' + _s.repeat('0', 9 - (512 + number).toString(2).length) + (512 + number).toString(2);
 3280-      }
 3281-
 3282-      // Convert decimal number to binary
 3283-      var result = parseInt(number, 10).toString(2);
 3284-
 3285-      // Return binary number using the minimum number of characters necessary if places is undefined
 3286-      if (typeof places === 'undefined') {
 3287-        return result;
 3288-      } else {
 3289-        // Return error if places is nonnumeric
 3290-        if (isNaN(places)) {
 3291-          return '#VALUE!';
 3292-        }
 3293-
 3294-        // Return error if places is negative
 3295-        if (places < 0) {
 3296-          return '#NUM!';
 3297-        }
 3298-
 3299-        // Truncate places in case it is not an integer
 3300-        places = Math.floor(places);
 3301-
 3302-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 3303-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 3304-      }
 3305-    };
 3306-
 3307-    Formula.DEC2HEX = function (number, places) {
 3308-      // Return error if number is not a number
 3309-      if (isNaN(number)) {
 3310-        return '#VALUE!';
 3311-      }
 3312-
 3313-      // Return error if number is not decimal, is lower than -549755813888, or is greater than 549755813887
 3314-      if (!/^-?[0-9]{1,12}$/.test(number) || number < -549755813888 || number > 549755813887) {
 3315-        return '#NUM!';
 3316-      }
 3317-
 3318-      // Ignore places and return a 10-character hexadecimal number if number is negative
 3319-      if (number < 0) {
 3320-        return (1099511627776 + number).toString(16);
 3321-      }
 3322-
 3323-      // Convert decimal number to hexadecimal
 3324-      var result = parseInt(number, 10).toString(16);
 3325-
 3326-      // Return hexadecimal number using the minimum number of characters necessary if places is undefined
 3327-      if (typeof places === 'undefined') {
 3328-        return result;
 3329-      } else {
 3330-        // Return error if places is nonnumeric
 3331-        if (isNaN(places)) {
 3332-          return '#VALUE!';
 3333-        }
 3334-
 3335-        // Return error if places is negative
 3336-        if (places < 0) {
 3337-          return '#NUM!';
 3338-        }
 3339-
 3340-        // Truncate places in case it is not an integer
 3341-        places = Math.floor(places);
 3342-
 3343-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 3344-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 3345-      }
 3346-    };
 3347-
 3348-    Formula.DEC2OCT = function (number, places) {
 3349-      // Return error if number is not a number
 3350-      if (isNaN(number)) {
 3351-        return '#VALUE!';
 3352-      }
 3353-
 3354-      // Return error if number is not decimal, is lower than -549755813888, or is greater than 549755813887
 3355-      if (!/^-?[0-9]{1,9}$/.test(number) || number < -536870912 || number > 536870911) {
 3356-        return '#NUM!';
 3357-      }
 3358-
 3359-      // Ignore places and return a 10-character octal number if number is negative
 3360-      if (number < 0) {
 3361-        return (1073741824 + number).toString(8);
 3362-      }
 3363-
 3364-      // Convert decimal number to octal
 3365-      var result = parseInt(number, 10).toString(8);
 3366-
 3367-      // Return octal number using the minimum number of characters necessary if places is undefined
 3368-      if (typeof places === 'undefined') {
 3369-        return result;
 3370-      } else {
 3371-        // Return error if places is nonnumeric
 3372-        if (isNaN(places)) {
 3373-          return '#VALUE!';
 3374-        }
 3375-
 3376-        // Return error if places is negative
 3377-        if (places < 0) {
 3378-          return '#NUM!';
 3379-        }
 3380-
 3381-        // Truncate places in case it is not an integer
 3382-        places = Math.floor(places);
 3383-
 3384-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 3385-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 3386-      }
 3387-    };
 3388-
 3389-    Formula.DELTA = function (number1, number2) {
 3390-      // Set number2 to zero if undefined
 3391-      number2 = (typeof number2 === 'undefined') ? 0 : number2;
 3392-
 3393-      // Return error if either number is not a number
 3394-      if (isNaN(number1) || isNaN(number2)) {
 3395-        return '#VALUE!';
 3396-      }
 3397-
 3398-      // Return delta
 3399-      return (number1 === number2) ? 1 : 0;
 3400-    };
 3401-
 3402-    Formula.ERF = function (lower_bound, upper_bound) {
 3403-      // Set number2 to zero if undefined
 3404-      upper_bound = (typeof upper_bound === 'undefined') ? 0 : upper_bound;
 3405-
 3406-      // Return error if either number is not a number
 3407-      if (isNaN(lower_bound) || isNaN(upper_bound)) {
 3408-        return '#VALUE!';
 3409-      }
 3410-
 3411-      // Return ERFC using jStat [http://www.jstat.org/]
 3412-      return jStat.erf(lower_bound);
 3413-    };
 3414-
 3415-    Formula.ERFC = function (x) {
 3416-      // Return error if x is not a number
 3417-      if (isNaN(x)) {
 3418-        return '#VALUE!';
 3419-      }
 3420-
 3421-      // Return ERFC using jStat [http://www.jstat.org/]
 3422-      return jStat.erfc(x);
 3423-    };
 3424-
 3425-    Formula.ERFCPRECISE = function () {
 3426-      return;
 3427-    };
 3428-
 3429-    Formula.ERFPRECISE = function () {
 3430-      return;
 3431-    };
 3432-
 3433-    Formula.GESTEP = function (number, step) {
 3434-      // Set step to zero if undefined
 3435-      step = (typeof step === 'undefined') ? 0 : step;
 3436-
 3437-      // Return error if either number is not a number
 3438-      if (isNaN(number) || isNaN(step)) {
 3439-        return '#VALUE!';
 3440-      }
 3441-
 3442-      // Return delta
 3443-      return (number >= step) ? 1 : 0;
 3444-    };
 3445-
 3446-    Formula.HEX2BIN = function (number, places) {
 3447-
 3448-      // Return error if number is not hexadecimal or contains more than ten characters (10 digits)
 3449-      if (!/^[0-9A-Fa-f]{1,10}$/.test(number)) {
 3450-        return '#NUM!';
 3451-      }
 3452-
 3453-      // Check if number is negative
 3454-      var negative = (number.length === 10 && number.substring(0, 1).toLowerCase() === 'f') ? true : false;
 3455-
 3456-      // Convert hexadecimal number to decimal
 3457-      var decimal = (negative) ? parseInt(number, 16) - 1099511627776 : parseInt(number, 16);
 3458-
 3459-      // Return error if number is lower than -512 or greater than 511
 3460-      if (decimal < -512 || decimal > 511) {
 3461-        return '#NUM!';
 3462-      }
 3463-
 3464-      // Ignore places and return a 10-character binary number if number is negative
 3465-      if (negative) {
 3466-        return '1' + _s.repeat('0', 9 - (512 + decimal).toString(2).length) + (512 + decimal).toString(2);
 3467-      }
 3468-
 3469-      // Convert decimal number to binary
 3470-      var result = decimal.toString(2);
 3471-
 3472-      // Return binary number using the minimum number of characters necessary if places is undefined
 3473-      if (typeof places === 'undefined') {
 3474-        return result;
 3475-      } else {
 3476-        // Return error if places is nonnumeric
 3477-        if (isNaN(places)) {
 3478-          return '#VALUE!';
 3479-        }
 3480-
 3481-        // Return error if places is negative
 3482-        if (places < 0) {
 3483-          return '#NUM!';
 3484-        }
 3485-
 3486-        // Truncate places in case it is not an integer
 3487-        places = Math.floor(places);
 3488-
 3489-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 3490-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 3491-      }
 3492-    };
 3493-
 3494-    Formula.HEX2DEC = function (number) {
 3495-      // Return error if number is not hexadecimal or contains more than ten characters (10 digits)
 3496-      if (!/^[0-9A-Fa-f]{1,10}$/.test(number)) {
 3497-        return '#NUM!';
 3498-      }
 3499-
 3500-      // Convert hexadecimal number to decimal
 3501-      var decimal = parseInt(number, 16);
 3502-
 3503-      // Return decimal number
 3504-      return (decimal >= 549755813888) ? decimal - 1099511627776 : decimal;
 3505-    };
 3506-
 3507-    Formula.HEX2OCT = function (number, places) {
 3508-      // Return error if number is not hexadecimal or contains more than ten characters (10 digits)
 3509-      if (!/^[0-9A-Fa-f]{1,10}$/.test(number)) {
 3510-        return '#NUM!';
 3511-      }
 3512-
 3513-      // Convert hexadecimal number to decimal
 3514-      var decimal = parseInt(number, 16);
 3515-
 3516-      // Return error if number is positive and greater than 0x1fffffff (536870911)
 3517-      if (decimal > 536870911 && decimal < 1098974756864) {
 3518-        return '#NUM!';
 3519-      }
 3520-
 3521-      // Ignore places and return a 10-character octal number if number is negative
 3522-      if (decimal >= 1098974756864) {
 3523-        return (decimal - 1098437885952).toString(8);
 3524-      }
 3525-
 3526-      // Convert decimal number to octal
 3527-      var result = decimal.toString(8);
 3528-
 3529-      // Return octal number using the minimum number of characters necessary if places is undefined
 3530-      if (typeof places === 'undefined') {
 3531-        return result;
 3532-      } else {
 3533-        // Return error if places is nonnumeric
 3534-        if (isNaN(places)) {
 3535-          return '#VALUE!';
 3536-        }
 3537-
 3538-        // Return error if places is negative
 3539-        if (places < 0) {
 3540-          return '#NUM!';
 3541-        }
 3542-
 3543-        // Truncate places in case it is not an integer
 3544-        places = Math.floor(places);
 3545-
 3546-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 3547-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 3548-      }
 3549-    };
 3550-
 3551-    Formula.IMABS = function (inumber) {
 3552-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3553-      var x = Formula.IMREAL(inumber);
 3554-      var y = Formula.IMAGINARY(inumber);
 3555-
 3556-      // Return error if either coefficient is not a number
 3557-      if (x === '#NUM!' || y === '#NUM!') {
 3558-        return '#NUM!';
 3559-      }
 3560-
 3561-      // Return absolute value of complex number
 3562-      return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
 3563-    };
 3564-
 3565-    Formula.IMAGINARY = function (inumber) {
 3566-      // Return 0 if inumber is equal to 0
 3567-      if (inumber === 0 || inumber === '0') {
 3568-        return 0;
 3569-      }
 3570-
 3571-      // Handle special cases
 3572-      if (['i', 'j'].indexOf(inumber) >= 0) {
 3573-        return 1;
 3574-      }
 3575-
 3576-      // Normalize imaginary coefficient
 3577-      inumber = inumber.replace('+i', '+1i').replace('-i', '-1i').replace('+j', '+1j').replace('-j', '-1j');
 3578-
 3579-      // Lookup sign
 3580-      var plus = inumber.indexOf('+');
 3581-      var minus = inumber.indexOf('-');
 3582-      if (plus === 0) {
 3583-        plus = inumber.indexOf('+', 1);
 3584-      }
 3585-
 3586-      if (minus === 0) {
 3587-        minus = inumber.indexOf('-', 1);
 3588-      }
 3589-
 3590-      // Lookup imaginary unit
 3591-      var last = inumber.substring(inumber.length - 1, inumber.length);
 3592-      var unit = (last === 'i' || last === 'j');
 3593-
 3594-      if (plus >= 0 || minus >= 0) {
 3595-        // Return error if imaginary unit is neither i nor j
 3596-        if (!unit) {
 3597-          return '#NUM!';
 3598-        }
 3599-
 3600-        // Return imaginary coefficient of complex number
 3601-        if (plus >= 0) {
 3602-          return (isNaN(inumber.substring(0, plus)) || isNaN(inumber.substring(plus + 1, inumber.length - 1))) ?
 3603-            '#NUM!' :
 3604-            Number(inumber.substring(plus + 1, inumber.length - 1));
 3605-        } else {
 3606-          return (isNaN(inumber.substring(0, minus)) || isNaN(inumber.substring(minus + 1, inumber.length - 1))) ?
 3607-            '#NUM!' :
 3608-            -Number(inumber.substring(minus + 1, inumber.length - 1));
 3609-        }
 3610-      } else {
 3611-        if (unit) {
 3612-          return (isNaN(inumber.substring(0, inumber.length - 1))) ? '#NUM!' : inumber.substring(0, inumber.length - 1);
 3613-        } else {
 3614-          return (isNaN(inumber)) ? '#NUM!' : 0;
 3615-        }
 3616-      }
 3617-    };
 3618-
 3619-    Formula.IMARGUMENT = function (inumber) {
 3620-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3621-      var x = Formula.IMREAL(inumber);
 3622-      var y = Formula.IMAGINARY(inumber);
 3623-
 3624-      // Return error if either coefficient is not a number
 3625-      if (x === '#NUM!' || y === '#NUM!') {
 3626-        return '#NUM!';
 3627-      }
 3628-
 3629-      // Return error if inumber is equal to zero
 3630-      if (x === 0 && y === 0) {
 3631-        return '#DIV/0!';
 3632-      }
 3633-
 3634-      // Return PI/2 if x is equal to zero and y is positive
 3635-      if (x === 0 && y > 0) {
 3636-        return Math.PI / 2;
 3637-      }
 3638-
 3639-      // Return -PI/2 if x is equal to zero and y is negative
 3640-      if (x === 0 && y < 0) {
 3641-        return -Math.PI / 2;
 3642-      }
 3643-
 3644-      // Return zero if x is negative and y is equal to zero
 3645-      if (y === 0 && x > 0) {
 3646-        return 0;
 3647-      }
 3648-
 3649-      // Return zero if x is negative and y is equal to zero
 3650-      if (y === 0 && x < 0) {
 3651-        return -Math.PI;
 3652-      }
 3653-
 3654-      // Return argument of complex number
 3655-      if (x > 0) {
 3656-        return Math.atan(y / x);
 3657-      } else if (x < 0 && y >= 0) {
 3658-        return Math.atan(y / x) + Math.PI;
 3659-      } else {
 3660-        return Math.atan(y / x) - Math.PI;
 3661-      }
 3662-    };
 3663-
 3664-    Formula.IMCONJUGATE = function (inumber) {
 3665-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3666-      var x = Formula.IMREAL(inumber);
 3667-      var y = Formula.IMAGINARY(inumber);
 3668-
 3669-      // Lookup imaginary unit
 3670-      var unit = inumber.substring(inumber.length - 1);
 3671-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3672-
 3673-      // Return error if either coefficient is not a number
 3674-      if (x === '#NUM!' || y === '#NUM!') {
 3675-        return '#NUM!';
 3676-      }
 3677-
 3678-      // Return conjugate of complex number
 3679-      return (y !== 0) ? Formula.COMPLEX(x, -y, unit) : inumber;
 3680-    };
 3681-
 3682-    Formula.IMCOS = function (inumber) {
 3683-      // Return error if inumber is a logical value
 3684-      if (inumber === true || inumber === false) {
 3685-        return '#VALUE!';
 3686-      }
 3687-
 3688-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3689-      var x = Formula.IMREAL(inumber);
 3690-      var y = Formula.IMAGINARY(inumber);
 3691-
 3692-      // Lookup imaginary unit
 3693-      var unit = inumber.substring(inumber.length - 1);
 3694-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3695-
 3696-      // Return error if either coefficient is not a number
 3697-      if (x === '#NUM!' || y === '#NUM!') {
 3698-        return '#NUM!';
 3699-      }
 3700-
 3701-      // Return cosine of complex number
 3702-      return Formula.COMPLEX(Math.cos(x) * (Math.exp(y) + Math.exp(-y)) / 2, -Math.sin(x) * (Math.exp(y) - Math.exp(-y)) / 2, unit);
 3703-    };
 3704-
 3705-    Formula.IMCOSH = function (inumber) {
 3706-      // Return error if inumber is a logical value
 3707-      if (inumber === true || inumber === false) {
 3708-        return '#VALUE!';
 3709-      }
 3710-
 3711-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3712-      var x = Formula.IMREAL(inumber);
 3713-      var y = Formula.IMAGINARY(inumber);
 3714-
 3715-      // Lookup imaginary unit
 3716-      var unit = inumber.substring(inumber.length - 1);
 3717-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3718-
 3719-      // Return error if either coefficient is not a number
 3720-      if (x === '#NUM!' || y === '#NUM!') {
 3721-        return '#NUM!';
 3722-      }
 3723-
 3724-      // Return hyperbolic cosine of complex number
 3725-      return Formula.COMPLEX(Math.cos(y) * (Math.exp(x) + Math.exp(-x)) / 2, Math.sin(y) * (Math.exp(x) - Math.exp(-x)) / 2, unit);
 3726-    };
 3727-
 3728-    Formula.IMCOT = function (inumber) {
 3729-      // Return error if inumber is a logical value
 3730-      if (inumber === true || inumber === false) {
 3731-        return '#VALUE!';
 3732-      }
 3733-
 3734-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3735-      var x = Formula.IMREAL(inumber);
 3736-      var y = Formula.IMAGINARY(inumber);
 3737-
 3738-      // Return error if either coefficient is not a number
 3739-      if (x === '#NUM!' || y === '#NUM!') {
 3740-        return '#NUM!';
 3741-      }
 3742-
 3743-      // Return cotangent of complex number
 3744-      return Formula.IMDIV(Formula.IMCOS(inumber), Formula.IMSIN(inumber));
 3745-    };
 3746-
 3747-    Formula.IMCSC = function (inumber) {
 3748-      // Return error if inumber is a logical value
 3749-      if (inumber === true || inumber === false) {
 3750-        return '#VALUE!';
 3751-      }
 3752-
 3753-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3754-      var x = Formula.IMREAL(inumber);
 3755-      var y = Formula.IMAGINARY(inumber);
 3756-
 3757-      // Return error if either coefficient is not a number
 3758-      if (x === '#NUM!' || y === '#NUM!') {
 3759-        return '#NUM!';
 3760-      }
 3761-
 3762-      // Return cosecant of complex number
 3763-      return Formula.IMDIV('1', Formula.IMSIN(inumber));
 3764-    };
 3765-
 3766-    Formula.IMCSCH = function (inumber) {
 3767-      // Return error if inumber is a logical value
 3768-      if (inumber === true || inumber === false) {
 3769-        return '#VALUE!';
 3770-      }
 3771-
 3772-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3773-      var x = Formula.IMREAL(inumber);
 3774-      var y = Formula.IMAGINARY(inumber);
 3775-
 3776-      // Return error if either coefficient is not a number
 3777-      if (x === '#NUM!' || y === '#NUM!') {
 3778-        return '#NUM!';
 3779-      }
 3780-
 3781-      // Return hyperbolic cosecant of complex number
 3782-      return Formula.IMDIV('1', Formula.IMSINH(inumber));
 3783-    };
 3784-
 3785-    Formula.IMDIV = function (inumber1, inumber2) {
 3786-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3787-      var a = Formula.IMREAL(inumber1);
 3788-      var b = Formula.IMAGINARY(inumber1);
 3789-      var c = Formula.IMREAL(inumber2);
 3790-      var d = Formula.IMAGINARY(inumber2);
 3791-
 3792-      // Lookup imaginary unit
 3793-      var unit1 = inumber1.substring(inumber1.length - 1);
 3794-      var unit2 = inumber1.substring(inumber1.length - 1);
 3795-      var unit = 'i';
 3796-      if (unit1 === 'j') {
 3797-        unit = 'j';
 3798-      } else if (unit2 === 'j') {
 3799-        unit = 'j';
 3800-      }
 3801-
 3802-      // Return error if either coefficient is not a number
 3803-      if (a === '#NUM!' || b === '#NUM!' || c === '#NUM!' || d === '#NUM!') {
 3804-        return '#NUM!';
 3805-      }
 3806-
 3807-      // Return error if inumber2 is null
 3808-      if (c === 0 && d === 0) {
 3809-        return '#NUM!';
 3810-      }
 3811-
 3812-      // Return exponential of complex number
 3813-      var den = c * c + d * d;
 3814-      return Formula.COMPLEX((a * c + b * d) / den, (b * c - a * d) / den, unit);
 3815-    };
 3816-
 3817-    Formula.IMEXP = function (inumber) {
 3818-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3819-      var x = Formula.IMREAL(inumber);
 3820-      var y = Formula.IMAGINARY(inumber);
 3821-
 3822-      // Lookup imaginary unit
 3823-      var unit = inumber.substring(inumber.length - 1);
 3824-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3825-
 3826-      // Return error if either coefficient is not a number
 3827-      if (x === '#NUM!' || y === '#NUM!') {
 3828-        return '#NUM!';
 3829-      }
 3830-
 3831-      // Return exponential of complex number
 3832-      var e = Math.exp(x);
 3833-      return Formula.COMPLEX(e * Math.cos(y), e * Math.sin(y), unit);
 3834-    };
 3835-
 3836-    Formula.IMLN = function (inumber) {
 3837-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3838-      var x = Formula.IMREAL(inumber);
 3839-      var y = Formula.IMAGINARY(inumber);
 3840-
 3841-      // Lookup imaginary unit
 3842-      var unit = inumber.substring(inumber.length - 1);
 3843-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3844-
 3845-      // Return error if either coefficient is not a number
 3846-      if (x === '#NUM!' || y === '#NUM!') {
 3847-        return '#NUM!';
 3848-      }
 3849-
 3850-      // Return exponential of complex number
 3851-      return Formula.COMPLEX(Math.log(Math.sqrt(x * x + y * y)), Math.atan(y / x), unit);
 3852-    };
 3853-
 3854-    Formula.IMLOG10 = function (inumber) {
 3855-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3856-      var x = Formula.IMREAL(inumber);
 3857-      var y = Formula.IMAGINARY(inumber);
 3858-
 3859-      // Lookup imaginary unit
 3860-      var unit = inumber.substring(inumber.length - 1);
 3861-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3862-
 3863-      // Return error if either coefficient is not a number
 3864-      if (x === '#NUM!' || y === '#NUM!') {
 3865-        return '#NUM!';
 3866-      }
 3867-
 3868-      // Return exponential of complex number
 3869-      return Formula.COMPLEX(Math.log(Math.sqrt(x * x + y * y)) / Math.log(10), Math.atan(y / x) / Math.log(10), unit);
 3870-    };
 3871-
 3872-    Formula.IMLOG2 = function (inumber) {
 3873-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3874-      var x = Formula.IMREAL(inumber);
 3875-      var y = Formula.IMAGINARY(inumber);
 3876-
 3877-      // Lookup imaginary unit
 3878-      var unit = inumber.substring(inumber.length - 1);
 3879-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3880-
 3881-      // Return error if either coefficient is not a number
 3882-      if (x === '#NUM!' || y === '#NUM!') {
 3883-        return '#NUM!';
 3884-      }
 3885-
 3886-      // Return exponential of complex number
 3887-      return Formula.COMPLEX(Math.log(Math.sqrt(x * x + y * y)) / Math.log(2), Math.atan(y / x) / Math.log(2), unit);
 3888-    };
 3889-
 3890-    Formula.IMPOWER = function (inumber, number) {
 3891-      // Return error if number is nonnumeric
 3892-      if (isNaN(number)) {
 3893-        return '#VALUE!';
 3894-      }
 3895-
 3896-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 3897-      var x = Formula.IMREAL(inumber);
 3898-      var y = Formula.IMAGINARY(inumber);
 3899-
 3900-      // Lookup imaginary unit
 3901-      var unit = inumber.substring(inumber.length - 1);
 3902-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 3903-
 3904-      // Return error if either coefficient is not a number
 3905-      if (x === '#NUM!' || y === '#NUM!') {
 3906-        return '#NUM!';
 3907-      }
 3908-
 3909-      // Calculate power of modulus
 3910-      var p = Math.pow(Formula.IMABS(inumber), number);
 3911-
 3912-      // Calculate argument
 3913-      var t = Formula.IMARGUMENT(inumber);
 3914-
 3915-      // Return exponential of complex number
 3916-      return Formula.COMPLEX(p * Math.cos(number * t), p * Math.sin(number * t), unit);
 3917-    };
 3918-
 3919-    Formula.IMPRODUCT = function () {
 3920-      // Initialize result
 3921-      var result = arguments[0];
 3922-
 3923-      // Loop on all numbers
 3924-      for (var i = 1; i < arguments.length; i++) {
 3925-        // Lookup coefficients of two complex numbers
 3926-        var a = Formula.IMREAL(result);
 3927-        var b = Formula.IMAGINARY(result);
 3928-        var c = Formula.IMREAL(arguments[i]);
 3929-        var d = Formula.IMAGINARY(arguments[i]);
 3930-
 3931-        // Return error if either coefficient is not a number
 3932-        if (a === '#NUM!' || b === '#NUM!' || c === '#NUM!' || d === '#NUM!') {
 3933-          return '#NUM!';
 3934-        }
 3935-
 3936-        // Complute product of two complex numbers
 3937-        result = Formula.COMPLEX(a * c - b * d, a * d + b * c);
 3938-      }
 3939-
 3940-      // Return product of complex numbers
 3941-      return result;
 3942-    };
 3943-
 3944-    Formula.IMREAL = function (inumber) {
 3945-      // Return 0 if inumber is equal to 0
 3946-      if (inumber === 0 || inumber === '0') {
 3947-        return 0;
 3948-      }
 3949-
 3950-      // Handle special cases
 3951-      if (['i', '+i', '1i', '+1i', '-i', '-1i', 'j', '+j', '1j', '+1j', '-j', '-1j'].indexOf(inumber) >= 0) {
 3952-        return 0;
 3953-      }
 3954-
 3955-      // Lookup sign
 3956-      var plus = inumber.indexOf('+');
 3957-      var minus = inumber.indexOf('-');
 3958-      if (plus === 0) {
 3959-        plus = inumber.indexOf('+', 1);
 3960-      }
 3961-      if (minus === 0) {
 3962-        minus = inumber.indexOf('-', 1);
 3963-      }
 3964-
 3965-      // Lookup imaginary unit
 3966-      var last = inumber.substring(inumber.length - 1, inumber.length);
 3967-      var unit = (last === 'i' || last === 'j');
 3968-
 3969-      if (plus >= 0 || minus >= 0) {
 3970-        // Return error if imaginary unit is neither i nor j
 3971-        if (!unit) {
 3972-          return '#NUM!';
 3973-        }
 3974-
 3975-        // Return real coefficient of complex number
 3976-        if (plus >= 0) {
 3977-          return (isNaN(inumber.substring(0, plus)) || isNaN(inumber.substring(plus + 1, inumber.length - 1))) ?
 3978-            '#NUM!' :
 3979-            Number(inumber.substring(0, plus));
 3980-        } else {
 3981-          return (isNaN(inumber.substring(0, minus)) || isNaN(inumber.substring(minus + 1, inumber.length - 1))) ?
 3982-            '#NUM!' :
 3983-            Number(inumber.substring(0, minus));
 3984-        }
 3985-      } else {
 3986-        if (unit) {
 3987-          return (isNaN(inumber.substring(0, inumber.length - 1))) ? '#NUM!' : 0;
 3988-        } else {
 3989-          return (isNaN(inumber)) ? '#NUM!' : inumber;
 3990-        }
 3991-      }
 3992-    };
 3993-
 3994-    Formula.IMSEC = function (inumber) {
 3995-      // Return error if inumber is a logical value
 3996-      if (inumber === true || inumber === false) {
 3997-        return '#VALUE!';
 3998-      }
 3999-
 4000-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 4001-      var x = Formula.IMREAL(inumber);
 4002-      var y = Formula.IMAGINARY(inumber);
 4003-
 4004-      // Return error if either coefficient is not a number
 4005-      if (x === '#NUM!' || y === '#NUM!') {
 4006-        return '#NUM!';
 4007-      }
 4008-
 4009-      // Return secant of complex number
 4010-      return Formula.IMDIV('1', Formula.IMCOS(inumber));
 4011-    };
 4012-
 4013-    Formula.IMSECH = function (inumber) {
 4014-      // Return error if inumber is a logical value
 4015-      if (inumber === true || inumber === false) {
 4016-        return '#VALUE!';
 4017-      }
 4018-
 4019-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 4020-      var x = Formula.IMREAL(inumber);
 4021-      var y = Formula.IMAGINARY(inumber);
 4022-
 4023-      // Return error if either coefficient is not a number
 4024-      if (x === '#NUM!' || y === '#NUM!') {
 4025-        return '#NUM!';
 4026-      }
 4027-
 4028-      // Return hyperbolic secant of complex number
 4029-      return Formula.IMDIV('1', Formula.IMCOSH(inumber));
 4030-    };
 4031-
 4032-    Formula.IMSIN = function (inumber) {
 4033-      // Return error if inumber is a logical value
 4034-      if (inumber === true || inumber === false) {
 4035-        return '#VALUE!';
 4036-      }
 4037-
 4038-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 4039-      var x = Formula.IMREAL(inumber);
 4040-      var y = Formula.IMAGINARY(inumber);
 4041-
 4042-      // Lookup imaginary unit
 4043-      var unit = inumber.substring(inumber.length - 1);
 4044-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 4045-
 4046-      // Return error if either coefficient is not a number
 4047-      if (x === '#NUM!' || y === '#NUM!') {
 4048-        return '#NUM!';
 4049-      }
 4050-
 4051-      // Return sine of complex number
 4052-      return Formula.COMPLEX(Math.sin(x) * (Math.exp(y) + Math.exp(-y)) / 2, Math.cos(x) * (Math.exp(y) - Math.exp(-y)) / 2, unit);
 4053-    };
 4054-
 4055-    Formula.IMSINH = function (inumber) {
 4056-      // Return error if inumber is a logical value
 4057-      if (inumber === true || inumber === false) {
 4058-        return '#VALUE!';
 4059-      }
 4060-
 4061-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 4062-      var x = Formula.IMREAL(inumber);
 4063-      var y = Formula.IMAGINARY(inumber);
 4064-
 4065-      // Lookup imaginary unit
 4066-      var unit = inumber.substring(inumber.length - 1);
 4067-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 4068-
 4069-      // Return error if either coefficient is not a number
 4070-      if (x === '#NUM!' || y === '#NUM!') {
 4071-        return '#NUM!';
 4072-      }
 4073-
 4074-      // Return hyperbolic sine of complex number
 4075-      return Formula.COMPLEX(Math.cos(y) * (Math.exp(x) - Math.exp(-x)) / 2, Math.sin(y) * (Math.exp(x) + Math.exp(-x)) / 2, unit);
 4076-    };
 4077-
 4078-    Formula.IMSQRT = function (inumber) {
 4079-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 4080-      var x = Formula.IMREAL(inumber);
 4081-      var y = Formula.IMAGINARY(inumber);
 4082-
 4083-      // Lookup imaginary unit
 4084-      var unit = inumber.substring(inumber.length - 1);
 4085-      unit = (unit === 'i' || unit === 'j') ? unit : 'i';
 4086-
 4087-      // Return error if either coefficient is not a number
 4088-      if (x === '#NUM!' || y === '#NUM!') {
 4089-        return '#NUM!';
 4090-      }
 4091-
 4092-      // Calculate power of modulus
 4093-      var s = Math.sqrt(Formula.IMABS(inumber));
 4094-
 4095-      // Calculate argument
 4096-      var t = Formula.IMARGUMENT(inumber);
 4097-
 4098-      // Return exponential of complex number
 4099-      return Formula.COMPLEX(s * Math.cos(t / 2), s * Math.sin(t / 2), unit);
 4100-    };
 4101-
 4102-    Formula.IMSUB = function (inumber1, inumber2) {
 4103-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 4104-      var a = Formula.IMREAL(inumber1);
 4105-      var b = Formula.IMAGINARY(inumber1);
 4106-      var c = Formula.IMREAL(inumber2);
 4107-      var d = Formula.IMAGINARY(inumber2);
 4108-
 4109-      // Lookup imaginary unit
 4110-      var unit1 = inumber1.substring(inumber1.length - 1);
 4111-      var unit2 = inumber1.substring(inumber1.length - 1);
 4112-      var unit = 'i';
 4113-      if (unit1 === 'j') {
 4114-        unit = 'j';
 4115-      } else if (unit2 === 'j') {
 4116-        unit = 'j';
 4117-      }
 4118-
 4119-      // Return error if either coefficient is not a number
 4120-      if (a === '#NUM!' || b === '#NUM!' || c === '#NUM!' || d === '#NUM!') {
 4121-        return '#NUM!';
 4122-      }
 4123-
 4124-      // Return _ of two complex numbers
 4125-      return Formula.COMPLEX(a - c, b - d, unit);
 4126-    };
 4127-
 4128-    Formula.IMSUM = function () {
 4129-      // Initialize result
 4130-      var result = arguments[0];
 4131-
 4132-      // Loop on all numbers
 4133-      for (var i = 1; i < arguments.length; i++) {
 4134-        // Lookup coefficients of two complex numbers
 4135-        var a = Formula.IMREAL(result);
 4136-        var b = Formula.IMAGINARY(result);
 4137-        var c = Formula.IMREAL(arguments[i]);
 4138-        var d = Formula.IMAGINARY(arguments[i]);
 4139-
 4140-        // Return error if either coefficient is not a number
 4141-        if (a === '#NUM!' || b === '#NUM!' || c === '#NUM!' || d === '#NUM!') {
 4142-          return '#NUM!';
 4143-        }
 4144-
 4145-        // Complute product of two complex numbers
 4146-        result = Formula.COMPLEX(a + c, b + d);
 4147-      }
 4148-
 4149-      // Return sum of complex numbers
 4150-      return result;
 4151-    };
 4152-
 4153-    Formula.IMTAN = function (inumber) {
 4154-      // Return error if inumber is a logical value
 4155-      if (inumber === true || inumber === false) {
 4156-        return '#VALUE!';
 4157-      }
 4158-
 4159-      // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org]
 4160-      var x = Formula.IMREAL(inumber);
 4161-      var y = Formula.IMAGINARY(inumber);
 4162-
 4163-      // Return error if either coefficient is not a number
 4164-      if (x === '#NUM!' || y === '#NUM!') {
 4165-        return '#NUM!';
 4166-      }
 4167-
 4168-      // Return tangent of complex number
 4169-      return Formula.IMDIV(Formula.IMSIN(inumber), Formula.IMCOS(inumber));
 4170-    };
 4171-
 4172-    Formula.OCT2BIN = function (number, places) {
 4173-      // Return error if number is not hexadecimal or contains more than ten characters (10 digits)
 4174-      if (!/^[0-7]{1,10}$/.test(number)) {
 4175-        return '#NUM!';
 4176-      }
 4177-
 4178-      // Check if number is negative
 4179-      var negative = (number.length === 10 && number.substring(0, 1) === '7') ? true : false;
 4180-
 4181-      // Convert octal number to decimal
 4182-      var decimal = (negative) ? parseInt(number, 8) - 1073741824 : parseInt(number, 8);
 4183-
 4184-      // Return error if number is lower than -512 or greater than 511
 4185-      if (decimal < -512 || decimal > 511) {
 4186-        return '#NUM!';
 4187-      }
 4188-
 4189-      // Ignore places and return a 10-character binary number if number is negative
 4190-      if (negative) {
 4191-        return '1' + _s.repeat('0', 9 - (512 + decimal).toString(2).length) + (512 + decimal).toString(2);
 4192-      }
 4193-
 4194-      // Convert decimal number to binary
 4195-      var result = decimal.toString(2);
 4196-
 4197-      // Return binary number using the minimum number of characters necessary if places is undefined
 4198-      if (typeof places === 'undefined') {
 4199-        return result;
 4200-      } else {
 4201-        // Return error if places is nonnumeric
 4202-        if (isNaN(places)) {
 4203-          return '#VALUE!';
 4204-        }
 4205-
 4206-        // Return error if places is negative
 4207-        if (places < 0) {
 4208-          return '#NUM!';
 4209-        }
 4210-
 4211-        // Truncate places in case it is not an integer
 4212-        places = Math.floor(places);
 4213-
 4214-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 4215-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 4216-      }
 4217-    };
 4218-
 4219-    Formula.OCT2DEC = function (number) {
 4220-      // Return error if number is not octal or contains more than ten characters (10 digits)
 4221-      if (!/^[0-7]{1,10}$/.test(number)) {
 4222-        return '#NUM!';
 4223-      }
 4224-
 4225-      // Convert octal number to decimal
 4226-      var decimal = parseInt(number, 8);
 4227-
 4228-      // Return decimal number
 4229-      return (decimal >= 536870912) ? decimal - 1073741824 : decimal;
 4230-    };
 4231-
 4232-    Formula.OCT2HEX = function (number, places) {
 4233-      // Return error if number is not octal or contains more than ten characters (10 digits)
 4234-      if (!/^[0-7]{1,10}$/.test(number)) {
 4235-        return '#NUM!';
 4236-      }
 4237-
 4238-      // Convert octal number to decimal
 4239-      var decimal = parseInt(number, 8);
 4240-
 4241-      // Ignore places and return a 10-character octal number if number is negative
 4242-      if (decimal >= 536870912) {
 4243-        return 'ff' + (decimal + 3221225472).toString(16);
 4244-      }
 4245-
 4246-      // Convert decimal number to hexadecimal
 4247-      var result = decimal.toString(16);
 4248-
 4249-      // Return hexadecimal number using the minimum number of characters necessary if places is undefined
 4250-      if (typeof places === 'undefined') {
 4251-        return result;
 4252-      } else {
 4253-        // Return error if places is nonnumeric
 4254-        if (isNaN(places)) {
 4255-          return '#VALUE!';
 4256-        }
 4257-
 4258-        // Return error if places is negative
 4259-        if (places < 0) {
 4260-          return '#NUM!';
 4261-        }
 4262-
 4263-        // Truncate places in case it is not an integer
 4264-        places = Math.floor(places);
 4265-
 4266-        // Pad return value with leading 0s (zeros) if necessary (using Underscore.string)
 4267-        return (places >= result.length) ? _s.repeat('0', places - result.length) + result : '#NUM!';
 4268-      }
 4269-    };
 4270-
 4271-
 4272-    // Financial functions
 4273-
 4274-    Formula.ACCRINT = function (issue, first, settlement, rate, par, frequency, basis, method) {
 4275-      // Return error if either date is invalid
 4276-      if (!moment(issue).isValid() || !moment(first).isValid() || !moment(settlement).isValid()) {
 4277-        return '#VALUE!';
 4278-      }
 4279-
 4280-      // Return error if either rate or par are lower than or equal to zero
 4281-      if (rate <= 0 || par <= 0) {
 4282-        return '#NUM!';
 4283-      }
 4284-
 4285-      // Return error if frequency is neither 1, 2, or 4
 4286-      if ([1, 2, 4].indexOf(frequency) === -1) {
 4287-        return '#NUM!';
 4288-      }
 4289-
 4290-      // Return error if basis is neither 0, 1, 2, 3, or 4
 4291-      if ([0, 1, 2, 3, 4].indexOf(basis) === -1) {
 4292-        return '#NUM!';
 4293-      }
 4294-
 4295-      // Return error if issue greater than or equal to settlement
 4296-      if (moment(issue).diff(moment(settlement)) >= 0) {
 4297-        return '#NUM!';
 4298-      }
 4299-
 4300-      // Set default values
 4301-      par = (typeof par === 'undefined') ? 0 : par;
 4302-      basis = (typeof basis === 'undefined') ? 0 : basis;
 4303-      method = (typeof method === 'undefined') ? true : method;
 4304-
 4305-      // Compute accrued interest
 4306-      var factor = 0;
 4307-      switch (basis) {
 4308-        case 0:
 4309-          // US (NASD) 30/360
 4310-          factor = Formula.YEARFRAC(issue, settlement, basis);
 4311-          break;
 4312-        case 1:
 4313-          // Actual/actual
 4314-          factor = Formula.YEARFRAC(issue, settlement, basis);
 4315-          break;
 4316-        case 2:
 4317-          // Actual/360
 4318-          factor = Formula.YEARFRAC(issue, settlement, basis);
 4319-          break;
 4320-        case 3:
 4321-          // Actual/365
 4322-          factor = Formula.YEARFRAC(issue, settlement, basis);
 4323-          break;
 4324-        case 4:
 4325-          // European 30/360
 4326-          factor = Formula.YEARFRAC(issue, settlement, basis);
 4327-          break;
 4328-      }
 4329-      return par * rate * factor;
 4330-    };
 4331-
 4332-    Formula.ACCRINTM = function () {
 4333-      return;
 4334-    };
 4335-
 4336-    Formula.AMORDEGRC = function () {
 4337-      return;
 4338-    };
 4339-
 4340-    Formula.AMORLINC = function () {
 4341-      return;
 4342-    };
 4343-
 4344-    Formula.COUPDAYBS = function () {
 4345-      return;
 4346-    };
 4347-
 4348-    Formula.COUPDAYS = function () {
 4349-      return;
 4350-    };
 4351-
 4352-    Formula.COUPDAYSNC = function () {
 4353-      return;
 4354-    };
 4355-
 4356-    Formula.COUPNCD = function () {
 4357-      return;
 4358-    };
 4359-
 4360-    Formula.COUPNUM = function () {
 4361-      return;
 4362-    };
 4363-
 4364-    Formula.COUPPCD = function () {
 4365-      return;
 4366-    };
 4367-
 4368-    Formula.CUMIPMT = function (rate, periods, value, start, end, type) {
 4369-      // Credits: algorithm inspired by Apache OpenOffice
 4370-      // Credits: Hannes Stiebitzhofer for the translations of function and variable names
 4371-      // Requires Formula.FV() and Formula.PMT() from Formula.js [http://stoic.com/formula/]
 4372-
 4373-      // Evaluate rate and periods (TODO: replace with secure expression evaluator)
 4374-      rate = eval(rate);
 4375-      periods = eval(periods);
 4376-
 4377-      // Return error if either rate, periods, or value are lower than or equal to zero
 4378-      if (rate <= 0 || periods <= 0 || value <= 0) {
 4379-        return '#NUM!';
 4380-      }
 4381-
 4382-      // Return error if start < 1, end < 1, or start > end
 4383-      if (start < 1 || end < 1 || start > end) {
 4384-        return '#NUM!';
 4385-      }
 4386-
 4387-      // Return error if type is neither 0 nor 1
 4388-      if (type !== 0 && type !== 1) {
 4389-        return '#NUM!';
 4390-      }
 4391-
 4392-      // Compute cumulative interest
 4393-      var payment = Formula.PMT(rate, periods, value, 0, type);
 4394-      var interest = 0;
 4395-
 4396-      if (start === 1) {
 4397-        if (type === 0) {
 4398-          interest = -value;
 4399-          start++;
 4400-        }
 4401-      }
 4402-
 4403-      for (var i = start; i <= end; i++) {
 4404-        if (type === 1) {
 4405-          interest += Formula.FV(rate, i - 2, payment, value, 1) - payment;
 4406-        } else {
 4407-          interest += Formula.FV(rate, i - 1, payment, value, 0);
 4408-        }
 4409-      }
 4410-      interest *= rate;
 4411-
 4412-      // Return cumulative interest
 4413-      return interest;
 4414-    };
 4415-
 4416-    Formula.CUMPRINC = function (rate, periods, value, start, end, type) {
 4417-      // Credits: algorithm inspired by Apache OpenOffice
 4418-      // Credits: Hannes Stiebitzhofer for the translations of function and variable names
 4419-      // Requires Formula.FV() and Formula.PMT() from Formula.js [http://stoic.com/formula/]
 4420-
 4421-      // Evaluate rate and periods (TODO: replace with secure expression evaluator)
 4422-      rate = eval(rate);
 4423-      periods = eval(periods);
 4424-
 4425-      // Return error if either rate, periods, or value are lower than or equal to zero
 4426-      if (rate <= 0 || periods <= 0 || value <= 0) {
 4427-        return '#NUM!';
 4428-      }
 4429-
 4430-      // Return error if start < 1, end < 1, or start > end
 4431-      if (start < 1 || end < 1 || start > end) {
 4432-        return '#NUM!';
 4433-      }
 4434-
 4435-      // Return error if type is neither 0 nor 1
 4436-      if (type !== 0 && type !== 1) {
 4437-        return '#NUM!';
 4438-      }
 4439-
 4440-      // Compute cumulative principal
 4441-      var payment = Formula.PMT(rate, periods, value, 0, type);
 4442-      var principal = 0;
 4443-      if (start === 1) {
 4444-        if (type === 0) {
 4445-          principal = payment + value * rate;
 4446-        } else {
 4447-          principal = payment;
 4448-        }
 4449-        start++;
 4450-      }
 4451-      for (var i = start; i <= end; i++) {
 4452-        if (type > 0) {
 4453-          principal += payment - (Formula.FV(rate, i - 2, payment, value, 1) - payment) * rate;
 4454-        } else {
 4455-          principal += payment - Formula.FV(rate, i - 1, payment, value, 0) * rate;
 4456-        }
 4457-      }
 4458-
 4459-      // Return cumulative principal
 4460-      return principal;
 4461-    };
 4462-
 4463-    Formula.DB = function (cost, salvage, life, period, month) {
 4464-      // Initialize month
 4465-      month = (typeof month === 'undefined') ? 12 : month;
 4466-
 4467-      // Return error if any of the parameters is not a number
 4468-      if (isNaN(cost) || isNaN(salvage) || isNaN(life) || isNaN(period) || isNaN(month)) {
 4469-        return '#VALUE!';
 4470-      }
 4471-
 4472-      // Return error if any of the parameters is negative   [
 4473-
 4474-      if (cost < 0 || salvage < 0 || life < 0 || period < 0) {
 4475-        return '#NUM!';
 4476-      }
 4477-
 4478-      // Return error if month is not an integer between 1 and 12
 4479-      if ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].indexOf(month) === -1) {
 4480-        return '#NUM!';
 4481-      }
 4482-
 4483-      // Return error if period is greater than life
 4484-      if (period > life) {
 4485-        return '#NUM!';
 4486-      }
 4487-
 4488-      // Return 0 (zero) if salvage is greater than or equal to cost
 4489-      if (salvage >= cost) {
 4490-        return 0;
 4491-      }
 4492-
 4493-      // Rate is rounded to three decimals places
 4494-      var rate = (1 - Math.pow(salvage / cost, 1 / life)).toFixed(3);
 4495-
 4496-      // Compute initial depreciation
 4497-      var initial = cost * rate * month / 12;
 4498-
 4499-      // Compute total depreciation
 4500-      var total = initial;
 4501-      var current = 0;
 4502-      var ceiling = (period === life) ? life - 1 : period;
 4503-      for (var i = 2; i <= ceiling; i++) {
 4504-        current = (cost - total) * rate;
 4505-        total += current;
 4506-      }
 4507-
 4508-      // Depreciation for the first and last periods are special cases
 4509-      if (period === 1) {
 4510-        // First period
 4511-        return initial;
 4512-      } else if (period === life) {
 4513-        // Last period
 4514-        return (cost - total) * rate;
 4515-      } else {
 4516-        return current;
 4517-      }
 4518-    };
 4519-
 4520-    Formula.DDB = function (cost, salvage, life, period, factor) {
 4521-      // Initialize factor
 4522-      factor = (typeof factor === 'undefined') ? 2 : factor;
 4523-
 4524-      // Return error if any of the parameters is not a number
 4525-      if (isNaN(cost) || isNaN(salvage) || isNaN(life) || isNaN(period) || isNaN(factor)) {
 4526-        return '#VALUE!';
 4527-      }
 4528-
 4529-      // Return error if any of the parameters is negative or if factor is null
 4530-      if (cost < 0 || salvage < 0 || life < 0 || period < 0 || factor <= 0) {
 4531-        return '#NUM!';
 4532-      }
 4533-
 4534-      // Return error if period is greater than life
 4535-      if (period > life) {
 4536-        return '#NUM!';
 4537-      }
 4538-
 4539-      // Return 0 (zero) if salvage is greater than or equal to cost
 4540-      if (salvage >= cost) {
 4541-        return 0;
 4542-      }
 4543-
 4544-      // Compute depreciation
 4545-      var total = 0;
 4546-      var current = 0;
 4547-      for (var i = 1; i <= period; i++) {
 4548-        current = Math.min((cost - total) * (factor / life), (cost - salvage - total));
 4549-        total += current;
 4550-      }
 4551-
 4552-      // Return depreciation
 4553-      return current;
 4554-    };
 4555-
 4556-    Formula.DISC = function () {
 4557-      return;
 4558-    };
 4559-
 4560-    Formula.DOLLARDE = function (dollar, fraction) {
 4561-      // Credits: algorithm inspired by Apache OpenOffice
 4562-
 4563-      // Return error if any of the parameters is not a number
 4564-      if (isNaN(dollar) || isNaN(fraction)) {
 4565-        return '#VALUE!';
 4566-      }
 4567-
 4568-      // Return error if fraction is negative
 4569-      if (fraction < 0) {
 4570-        return '#NUM!';
 4571-      }
 4572-
 4573-      // Return error if fraction is greater than or equal to 0 and less than 1
 4574-      if (fraction >= 0 && fraction < 1) {
 4575-        return '#DIV/0!';
 4576-      }
 4577-
 4578-      // Truncate fraction if it is not an integer
 4579-      fraction = parseInt(fraction, 10);
 4580-
 4581-      // Compute integer part
 4582-      var result = parseInt(dollar, 10);
 4583-
 4584-      // Add decimal part
 4585-      result += (dollar % 1) * Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN10)) / fraction;
 4586-
 4587-      // Round result
 4588-      var power = Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN2) + 1);
 4589-      result = Math.round(result * power) / power;
 4590-
 4591-      // Return converted dollar price
 4592-      return result;
 4593-    };
 4594-
 4595-    Formula.DOLLARFR = function (dollar, fraction) {
 4596-      // Credits: algorithm inspired by Apache OpenOffice
 4597-
 4598-      // Return error if any of the parameters is not a number
 4599-      if (isNaN(dollar) || isNaN(fraction)) {
 4600-        return '#VALUE!';
 4601-      }
 4602-
 4603-      // Return error if fraction is negative
 4604-      if (fraction < 0) {
 4605-        return '#NUM!';
 4606-      }
 4607-
 4608-      // Return error if fraction is greater than or equal to 0 and less than 1
 4609-      if (fraction >= 0 && fraction < 1) {
 4610-        return '#DIV/0!';
 4611-      }
 4612-
 4613-      // Truncate fraction if it is not an integer
 4614-      fraction = parseInt(fraction, 10);
 4615-
 4616-      // Compute integer part
 4617-      var result = parseInt(dollar, 10);
 4618-
 4619-      // Add decimal part
 4620-      result += (dollar % 1) * Math.pow(10, -Math.ceil(Math.log(fraction) / Math.LN10)) * fraction;
 4621-
 4622-      // Return converted dollar price
 4623-      return result;
 4624-    };
 4625-
 4626-    Formula.DURATION = function () {
 4627-      return;
 4628-    };
 4629-
 4630-    Formula.EFFECT = function (rate, periods) {
 4631-      // Return error if any of the parameters is not a number
 4632-      if (isNaN(rate) || isNaN(periods)) {
 4633-        return '#VALUE!';
 4634-      }
 4635-
 4636-      // Return error if rate <=0 or periods < 1
 4637-      if (rate <= 0 || periods < 1) {
 4638-        return '#NUM!';
 4639-      }
 4640-
 4641-      // Truncate periods if it is not an integer
 4642-      periods = parseInt(periods, 10);
 4643-
 4644-      // Return effective annual interest rate
 4645-      return Math.pow(1 + rate / periods, periods) - 1;
 4646-    };
 4647-
 4648-    Formula.FV = function (rate, periods, payment, value, type) {
 4649-      // Credits: algorithm inspired by Apache OpenOffice
 4650-
 4651-      // Initialize type
 4652-      type = (typeof type === 'undefined') ? 0 : type;
 4653-
 4654-      // Evaluate rate (TODO: replace with secure expression evaluator)
 4655-      rate = eval(rate);
 4656-
 4657-      // Return future value
 4658-      var result;
 4659-      if (rate === 0) {
 4660-        result = value + payment * periods;
 4661-      } else {
 4662-        var term = Math.pow(1 + rate, periods);
 4663-        if (type === 1) {
 4664-          result = value * term + payment * (1 + rate) * (term - 1.0) / rate;
 4665-        } else {
 4666-          result = value * term + payment * (term - 1) / rate;
 4667-        }
 4668-      }
 4669-      return -result;
 4670-    };
 4671-
 4672-    Formula.FVSCHEDULE = function (principal, schedule) {
 4673-      // Initialize future value
 4674-      var future = principal;
 4675-
 4676-      // Apply all interests in schedule
 4677-      for (var i = 0; i < schedule.length; i++) {
 4678-        // Return error if schedule value is not a number
 4679-        if (isNaN(schedule[i])) {
 4680-          return '#VALUE!';
 4681-        }
 4682-
 4683-        // Apply scheduled interest
 4684-        future *= 1 + schedule[i];
 4685-      }
 4686-
 4687-      // Return future value
 4688-      return future;
 4689-    };
 4690-
 4691-    Formula.INTRATE = function () {
 4692-      return;
 4693-    };
 4694-
 4695-    Formula.IPMT = function (rate, period, periods, present, future, type) {
 4696-      // Credits: algorithm inspired by Apache OpenOffice
 4697-
 4698-      // Initialize type
 4699-      type = (typeof type === 'undefined') ? 0 : type;
 4700-
 4701-      // Evaluate rate and periods (TODO: replace with secure expression evaluator)
 4702-      rate = eval(rate);
 4703-      periods = eval(periods);
 4704-
 4705-      // Compute payment
 4706-      var payment = Formula.PMT(rate, periods, present, future, type);
 4707-
 4708-      // Compute interest
 4709-      var interest;
 4710-      if (period === 1) {
 4711-        if (type === 1) {
 4712-          interest = 0;
 4713-        } else {
 4714-          interest = -present;
 4715-        }
 4716-      } else {
 4717-        if (type === 1) {
 4718-          interest = Formula.FV(rate, period - 2, payment, present, 1) - payment;
 4719-        } else {
 4720-          interest = Formula.FV(rate, period - 1, payment, present, 0);
 4721-        }
 4722-      }
 4723-
 4724-      // Return interest
 4725-      return interest * rate;
 4726-    };
 4727-
 4728-    Formula.IRR = function (values, guess) {
 4729-      // Credits: algorithm inspired by Apache OpenOffice
 4730-
 4731-      // flatten so multi dimensional ranges also work
 4732-      values = Formula.FLATTEN(values);
 4733-
 4734-      // Calculates the resulting amount
 4735-      var irrResult = function (values, dates, rate) {
 4736-        var r = rate + 1;
 4737-        var result = values[0];
 4738-        for (var i = 1; i < values.length; i++) {
 4739-          result += values[i] / Math.pow(r, (dates[i] - dates[0]) / 365);
 4740-        }
 4741-        return result;
 4742-      };
 4743-
 4744-      // Calculates the first derivation
 4745-      var irrResultDeriv = function (values, dates, rate) {
 4746-        var r = rate + 1;
 4747-        var result = 0;
 4748-        for (var i = 1; i < values.length; i++) {
 4749-          var frac = (dates[i] - dates[0]) / 365;
 4750-          result -= frac * values[i] / Math.pow(r, frac + 1);
 4751-        }
 4752-        return result;
 4753-      };
 4754-
 4755-      // Initialize dates and check that values contains at least one positive value and one negative value
 4756-      var dates = [];
 4757-      var positive = false;
 4758-      var negative = false;
 4759-      for (var i = 0; i < values.length; i++) {
 4760-        dates[i] = (i === 0) ? 0 : dates[i - 1] + 365;
 4761-        if (values[i] > 0) {
 4762-          positive = true;
 4763-        }
 4764-        if (values[i] < 0) {
 4765-          negative = true;
 4766-        }
 4767-      }
 4768-
 4769-      // Return error if values does not contain at least one positive value and one negative value
 4770-      if (!positive || !negative) {
 4771-        return '#NUM!';
 4772-      }
 4773-
 4774-      // Initialize guess and resultRate
 4775-      guess = (typeof guess === 'undefined') ? 0.1 : guess;
 4776-      var resultRate = guess;
 4777-
 4778-      // Set maximum epsilon for end of iteration
 4779-      var epsMax = 1e-10;
 4780-
 4781-      // Set maximum number of iterations
 4782-      var iterMax = 50;
 4783-
 4784-      // Implement Newton's method
 4785-      var newRate, epsRate, resultValue;
 4786-      var iteration = 0;
 4787-      var contLoop = true;
 4788-      do {
 4789-        resultValue = irrResult(values, dates, resultRate);
 4790-        newRate = resultRate - resultValue / irrResultDeriv(values, dates, resultRate);
 4791-        epsRate = Math.abs(newRate - resultRate);
 4792-        resultRate = newRate;
 4793-        contLoop = (epsRate > epsMax) && (Math.abs(resultValue) > epsMax);
 4794-      } while (contLoop && (++iteration < iterMax));
 4795-
 4796-      if (contLoop) {
 4797-        return '#NUM!';
 4798-      }
 4799-
 4800-      // Return internal rate of return
 4801-      return resultRate;
 4802-    };
 4803-
 4804-    Formula.ISPMT = function (rate, period, periods, value) {
 4805-      // Evaluate rate and periods (TODO: replace with secure expression evaluator)
 4806-      rate = eval(rate);
 4807-      periods = eval(periods);
 4808-
 4809-      // Return interest
 4810-      return value * rate * (period / periods - 1);
 4811-    };
 4812-
 4813-    Formula.MDURATION = function () {
 4814-      return;
 4815-    };
 4816-
 4817-    Formula.MIRR = function (values, finance_rate, reinvest_rate) {
 4818-      // Initialize number of values
 4819-      var n = values.length;
 4820-
 4821-      // Lookup payments (negative values) and incomes (positive values)
 4822-      var payments = [];
 4823-      var incomes = [];
 4824-      for (var i = 0; i < n; i++) {
 4825-        if (values[i] < 0) {
 4826-          payments.push(values[i]);
 4827-        } else {
 4828-          incomes.push(values[i]);
 4829-        }
 4830-      }
 4831-
 4832-      // Return modified internal rate of return
 4833-      var num = -Formula.NPV(reinvest_rate, incomes) * Math.pow(1 + reinvest_rate, n - 1);
 4834-      var den = Formula.NPV(finance_rate, payments) * (1 + finance_rate);
 4835-      return Math.pow(num / den, 1 / (n - 1)) - 1;
 4836-    };
 4837-
 4838-    Formula.NOMINAL = function (rate, periods) {
 4839-      // Return error if any of the parameters is not a number
 4840-      if (isNaN(rate) || isNaN(periods)) {
 4841-        return '#VALUE!';
 4842-      }
 4843-
 4844-      // Return error if rate <=0 or periods < 1
 4845-      if (rate <= 0 || periods < 1) {
 4846-        return '#NUM!';
 4847-      }
 4848-
 4849-      // Truncate periods if it is not an integer
 4850-      periods = parseInt(periods, 10);
 4851-
 4852-      // Return nominal annual interest rate
 4853-      return (Math.pow(rate + 1, 1 / periods) - 1) * periods;
 4854-    };
 4855-
 4856-    Formula.NPER = function (rate, payment, present, future, type) {
 4857-      // Initialize type
 4858-      type = (typeof type === 'undefined') ? 0 : type;
 4859-
 4860-      // Initialize future value
 4861-      future = (typeof future === 'undefined') ? 0 : future;
 4862-
 4863-      // Evaluate rate and periods (TODO: replace with secure expression evaluator)
 4864-      rate = eval(rate);
 4865-
 4866-      // Return number of periods
 4867-      var num = payment * (1 + rate * type) - future * rate;
 4868-      var den = (present * rate + payment * (1 + rate * type));
 4869-      return Math.log(num / den) / Math.log(1 + rate);
 4870-    };
 4871-
 4872-    Formula.NPV = function () {
 4873-      // Cast arguments to array
 4874-      var args = [];
 4875-      for (var i = 0; i < arguments.length; i++) {
 4876-        args = args.concat(arguments[i]);
 4877-      }
 4878-
 4879-      // Lookup rate
 4880-      var rate = args[0];
 4881-
 4882-      // Initialize net present value
 4883-      var value = 0;
 4884-
 4885-      // Loop on all values
 4886-      for (var j = 1; j < args.length; j++) {
 4887-        value += args[j] / Math.pow(1 + rate, j);
 4888-      }
 4889-
 4890-      // Return net present value
 4891-      return value;
 4892-    };
 4893-
 4894-    Formula.ODDFPRICE = function () {
 4895-      return;
 4896-    };
 4897-
 4898-    Formula.ODDFYIELD = function () {
 4899-      return;
 4900-    };
 4901-
 4902-    Formula.ODDLPRICE = function () {
 4903-      return;
 4904-    };
 4905-
 4906-    Formula.ODDLYIELD = function () {
 4907-      return;
 4908-    };
 4909-
 4910-    Formula.PDURATION = function (rate, present, future) {
 4911-      // Return error if any of the parameters is not a number
 4912-      if (isNaN(rate) || isNaN(present) || isNaN(future)) {
 4913-        return '#VALUE!';
 4914-      }
 4915-
 4916-      // Return error if rate <=0
 4917-      if (rate <= 0) {
 4918-        return '#NUM!';
 4919-      }
 4920-
 4921-      // Return number of periods
 4922-      return (Math.log(future) - Math.log(present)) / Math.log(1 + rate);
 4923-    };
 4924-
 4925-    Formula.PMT = function (rate, periods, present, future, type) {
 4926-      // Credits: algorithm inspired by Apache OpenOffice
 4927-
 4928-      // Initialize type
 4929-      type = (typeof type === 'undefined') ? 0 : type;
 4930-
 4931-      // Evaluate rate and periods (TODO: replace with secure expression evaluator)
 4932-      rate = eval(rate);
 4933-      periods = eval(periods);
 4934-
 4935-      // Return payment
 4936-      var result;
 4937-      if (rate === 0) {
 4938-        result = (present + future) / periods;
 4939-      } else {
 4940-        var term = Math.pow(1 + rate, periods);
 4941-        if (type === 1) {
 4942-          result = (future * rate / (term - 1) + present * rate / (1 - 1 / term)) / (1 + rate);
 4943-        } else {
 4944-          result = future * rate / (term - 1) + present * rate / (1 - 1 / term);
 4945-        }
 4946-      }
 4947-      return -result;
 4948-    };
 4949-
 4950-    Formula.PPMT = function (rate, period, periods, present, future, type) {
 4951-      return Formula.PMT(rate, periods, present, future, type) - Formula.IPMT(rate, period, periods, present, future, type);
 4952-    };
 4953-
 4954-    Formula.PRICE = function () {
 4955-      return;
 4956-    };
 4957-
 4958-    Formula.PRICEDISC = function () {
 4959-      return;
 4960-    };
 4961-
 4962-    Formula.PRICEMAT = function () {
 4963-      return;
 4964-    };
 4965-
 4966-    Formula.PV = function (rate, periods, payment, future, type) {
 4967-      // Initialize type
 4968-      type = (typeof type === 'undefined') ? 0 : type;
 4969-
 4970-      // Evaluate rate and periods (TODO: replace with secure expression evaluator)
 4971-      rate = eval(rate);
 4972-      periods = eval(periods);
 4973-
 4974-      // Return present value
 4975-      if (rate === 0) {
 4976-        return -payment * periods - future;
 4977-      } else {
 4978-        return (((1 - Math.pow(1 + rate, periods)) / rate) * payment * (1 + rate * type) - future) / Math.pow(1 + rate, periods);
 4979-      }
 4980-    };
 4981-
 4982-    Formula.RATE = function (periods, payment, present, future, type, guess) {
 4983-      // Credits: rabugento
 4984-
 4985-      // Initialize guess
 4986-      guess = (typeof guess === 'undefined') ? 0.01 : guess;
 4987-
 4988-      // Initialize future
 4989-      future = (typeof future === 'undefined') ? 0 : future;
 4990-
 4991-      // Initialize type
 4992-      type = (typeof type === 'undefined') ? 0 : type;
 4993-
 4994-      // Evaluate periods (TODO: replace with secure expression evaluator)
 4995-      periods = eval(periods);
 4996-
 4997-      // Set maximum epsilon for end of iteration
 4998-      var epsMax = 1e-10;
 4999-
 5000-      // Set maximum number of iterations
 5001-      var iterMax = 50;
 5002-
 5003-      // Implement Newton's method
 5004-      var y, y0, y1, x0, x1 = 0, f = 0, i = 0;
 5005-      var rate = guess;
 5006-      if (Math.abs(rate) < epsMax) {
 5007-        y = present * (1 + periods * rate) + payment * (1 + rate * type) * periods + future;
 5008-      } else {
 5009-        f = Math.exp(periods * Math.log(1 + rate));
 5010-        y = present * f + payment * (1 / rate + type) * (f - 1) + future;
 5011-      }
 5012-      y0 = present + payment * periods + future;
 5013-      y1 = present * f + payment * (1 / rate + type) * (f - 1) + future;
 5014-      i = x0 = 0;
 5015-      x1 = rate;
 5016-      while ((Math.abs(y0 - y1) > epsMax) && (i < iterMax)) {
 5017-        rate = (y1 * x0 - y0 * x1) / (y1 - y0);
 5018-        x0 = x1;
 5019-        x1 = rate;
 5020-        if (Math.abs(rate) < epsMax) {
 5021-          y = present * (1 + periods * rate) + payment * (1 + rate * type) * periods + future;
 5022-        } else {
 5023-          f = Math.exp(periods * Math.log(1 + rate));
 5024-          y = present * f + payment * (1 / rate + type) * (f - 1) + future;
 5025-        }
 5026-        y0 = y1;
 5027-        y1 = y;
 5028-        ++i;
 5029-      }
 5030-      return rate;
 5031-    };
 5032-
 5033-    Formula.RECEIVED = function () {
 5034-      return;
 5035-    };
 5036-
 5037-    Formula.RRI = function (periods, present, future) {
 5038-      // Return error if any of the parameters is not a number
 5039-      if (isNaN(periods) || isNaN(present) || isNaN(future)) {
 5040-        return '#VALUE!';
 5041-      }
 5042-
 5043-      // Return error if periods or present is equal to 0 (zero)
 5044-      if (periods === 0 || present === 0) {
 5045-        return '#NUM!';
 5046-      }
 5047-
 5048-      // Return equivalent interest rate
 5049-      return Math.pow(future / present, 1 / periods) - 1;
 5050-    };
 5051-
 5052-    Formula.SLN = function (cost, salvage, life) {
 5053-      // Return error if any of the parameters is not a number
 5054-      if (isNaN(cost) || isNaN(salvage) || isNaN(life)) {
 5055-        return '#VALUE!';
 5056-      }
 5057-
 5058-      // Return error if life equal to 0 (zero)
 5059-      if (life === 0) {
 5060-        return '#NUM!';
 5061-      }
 5062-
 5063-      // Return straight-line depreciation
 5064-      return (cost - salvage) / life;
 5065-    };
 5066-
 5067-    Formula.SYD = function (cost, salvage, life, period) {
 5068-      // Return error if any of the parameters is not a number
 5069-      if (isNaN(cost) || isNaN(salvage) || isNaN(life) || isNaN(period)) {
 5070-        return '#VALUE!';
 5071-      }
 5072-
 5073-      // Return error if life equal to 0 (zero)
 5074-      if (life === 0) {
 5075-        return '#NUM!';
 5076-      }
 5077-
 5078-      // Return error if period is lower than 1 or greater than life
 5079-      if (period < 1 || period > life) {
 5080-        return '#NUM!';
 5081-      }
 5082-
 5083-      // Truncate period if it is not an integer
 5084-      period = parseInt(period, 10);
 5085-
 5086-      // Return straight-line depreciation
 5087-      return (cost - salvage) * (life - period + 1) * 2 / (life * (life + 1));
 5088-    };
 5089-
 5090-    Formula.TBILLEQ = function (settlement, maturity, discount) {
 5091-      // Return error if either date is invalid
 5092-      if (!moment(settlement).isValid() || !moment(maturity).isValid()) {
 5093-        return '#VALUE!';
 5094-      }
 5095-
 5096-      // Return error if discount is lower than or equal to zero
 5097-      if (discount <= 0) {
 5098-        return '#NUM!';
 5099-      }
 5100-
 5101-      // Return error if settlement is greater than maturity
 5102-      if (moment(settlement).diff(moment(maturity)) > 0) {
 5103-        return '#NUM!';
 5104-      }
 5105-
 5106-      // Return error if maturity is more than one year after settlement
 5107-      if (moment(maturity).diff(moment(settlement), 'years') > 1) {
 5108-        return '#NUM!';
 5109-      }
 5110-
 5111-      // Return bond-equivalent yield
 5112-      return (365 * discount) / (360 - discount * Formula.DAYS360(settlement, maturity));
 5113-    };
 5114-
 5115-    Formula.TBILLPRICE = function (settlement, maturity, discount) {
 5116-      // Return error if either date is invalid
 5117-      if (!moment(settlement).isValid() || !moment(maturity).isValid()) {
 5118-        return '#VALUE!';
 5119-      }
 5120-
 5121-      // Return error if discount is lower than or equal to zero
 5122-      if (discount <= 0) {
 5123-        return '#NUM!';
 5124-      }
 5125-
 5126-      // Return error if settlement is greater than maturity
 5127-      if (moment(settlement).diff(moment(maturity)) > 0) {
 5128-        return '#NUM!';
 5129-      }
 5130-
 5131-      // Return error if maturity is more than one year after settlement
 5132-      if (moment(maturity).diff(moment(settlement), 'years') > 1) {
 5133-        return '#NUM!';
 5134-      }
 5135-
 5136-      // Return bond-equivalent yield
 5137-      return 100 * (1 - discount * Formula.DAYS360(settlement, maturity) / 360);
 5138-    };
 5139-
 5140-    Formula.TBILLYIELD = function (settlement, maturity, price) {
 5141-      // Return error if either date is invalid
 5142-      if (!moment(settlement).isValid() || !moment(maturity).isValid()) {
 5143-        return '#VALUE!';
 5144-      }
 5145-
 5146-      // Return error if price is lower than or equal to zero
 5147-      if (price <= 0) {
 5148-        return '#NUM!';
 5149-      }
 5150-
 5151-      // Return error if settlement is greater than maturity
 5152-      if (moment(settlement).diff(moment(maturity)) > 0) {
 5153-        return '#NUM!';
 5154-      }
 5155-
 5156-      // Return error if maturity is more than one year after settlement
 5157-      if (moment(maturity).diff(moment(settlement), 'years') > 1) {
 5158-        return '#NUM!';
 5159-      }
 5160-
 5161-      // Return bond-equivalent yield
 5162-      return (100 - price) * 360 / (price * Formula.DAYS360(settlement, maturity));
 5163-    };
 5164-
 5165-    Formula.VDB = function () {
 5166-      return;
 5167-    };
 5168-
 5169-
 5170-    Formula.XIRR = function (values, dates, guess) {
 5171-      // Credits: algorithm inspired by Apache OpenOffice
 5172-
 5173-      // Calculates the resulting amount
 5174-      var irrResult = function (values, dates, rate) {
 5175-        var r = rate + 1;
 5176-        var result = values[0];
 5177-        for (var i = 1; i < values.length; i++) {
 5178-          result += values[i] / Math.pow(r, moment(dates[i]).diff(moment(dates[0]), 'days') / 365);
 5179-        }
 5180-        return result;
 5181-      };
 5182-
 5183-      // Calculates the first derivation
 5184-      var irrResultDeriv = function (values, dates, rate) {
 5185-        var r = rate + 1;
 5186-        var result = 0;
 5187-        for (var i = 1; i < values.length; i++) {
 5188-          var frac = moment(dates[i]).diff(moment(dates[0]), 'days') / 365;
 5189-          result -= frac * values[i] / Math.pow(r, frac + 1);
 5190-        }
 5191-        return result;
 5192-      };
 5193-
 5194-      // Check that values contains at least one positive value and one negative value
 5195-      var positive = false;
 5196-      var negative = false;
 5197-      for (var i = 0; i < values.length; i++) {
 5198-        if (values[i] > 0) {
 5199-          positive = true;
 5200-        }
 5201-        if (values[i] < 0) {
 5202-          negative = true;
 5203-        }
 5204-      }
 5205-
 5206-      // Return error if values does not contain at least one positive value and one negative value
 5207-      if (!positive || !negative) {
 5208-        return '#NUM!';
 5209-      }
 5210-
 5211-      // Initialize guess and resultRate
 5212-      guess = guess || 0.1;
 5213-      var resultRate = guess;
 5214-
 5215-      // Set maximum epsilon for end of iteration
 5216-      var epsMax = 1e-10;
 5217-
 5218-      // Set maximum number of iterations
 5219-      var iterMax = 50;
 5220-
 5221-      // Implement Newton's method
 5222-      var newRate, epsRate, resultValue;
 5223-      var iteration = 0;
 5224-      var contLoop = true;
 5225-      do {
 5226-        resultValue = irrResult(values, dates, resultRate);
 5227-        newRate = resultRate - resultValue / irrResultDeriv(values, dates, resultRate);
 5228-        epsRate = Math.abs(newRate - resultRate);
 5229-        resultRate = newRate;
 5230-        contLoop = (epsRate > epsMax) && (Math.abs(resultValue) > epsMax);
 5231-      } while (contLoop && (++iteration < iterMax));
 5232-
 5233-      if (contLoop) {
 5234-        return '#NUM!';
 5235-      }
 5236-
 5237-      // Return internal rate of return
 5238-      return resultRate;
 5239-    };
 5240-
 5241-    Formula.XNPV = function (rate, values, dates) {
 5242-      var result = 0;
 5243-      for (var i = 0; i < values.length; i++) {
 5244-        result += values[i] / Math.pow(1 + rate, moment(dates[i]).diff(moment(dates[0]), 'days') / 365);
 5245-      }
 5246-      return result;
 5247-    };
 5248-
 5249-    Formula.YIELD = function () {
 5250-      return;
 5251-    };
 5252-
 5253-    Formula.YIELDDISC = function () {
 5254-      return;
 5255-    };
 5256-
 5257-    Formula.YIELDMAT = function () {
 5258-    };
 5259-
 5260-
 5261-    // Information functions
 5262-
 5263-    Formula.ISNUMBER = function (number) {
 5264-      return (!isNaN(parseFloat(number)) && isFinite(number)) ? true : false;
 5265-    };
 5266-
 5267-
 5268-    // Logical functions
 5269-
 5270-    Formula.AND = function () {
 5271-      var result = true;
 5272-      for (var i = 0; i < arguments.length; i++) {
 5273-        if (!arguments[i]) {
 5274-          result = false;
 5275-        }
 5276-      }
 5277-      return result;
 5278-    };
 5279-
 5280-    Formula.FALSE = function () {
 5281-      return false;
 5282-    };
 5283-
 5284-    Formula.SWITCH = function () {
 5285-      var result;
 5286-      if (arguments.length > 0)  {
 5287-        var targetValue = arguments[0];
 5288-        var argc = arguments.length - 1;
 5289-        var switchCount = Math.floor(argc / 2);
 5290-        var switchSatisfied = false;
 5291-        var defaultClause = argc % 2 === 0 ? null : arguments[arguments.length - 1];
 5292-
 5293-        if (switchCount) {
 5294-          for (var index = 0; index < switchCount; index++) {
 5295-            if (targetValue === arguments[index * 2 + 1]) {
 5296-              result = arguments[index * 2 + 2];
 5297-              switchSatisfied = true;
 5298-              break;
 5299-            }
 5300-          }
 5301-        }
 5302-
 5303-        if (!switchSatisfied && defaultClause) {
 5304-          result = defaultClause;
 5305-        }
 5306-      }
 5307-
 5308-      return result;
 5309-    };
 5310-
 5311-    Formula.IF = function (test, then_value, otherwise_value) {
 5312-      return test?then_value:otherwise_value;
 5313-    };
 5314-
 5315-    Formula.IFNA = function (value, value_if_na) {
 5316-      return (value === '#N/A') ? value_if_na : value;
 5317-    };
 5318-
 5319-    Formula.NOT = function (logical) {
 5320-      return !logical;
 5321-    };
 5322-
 5323-    Formula.OR = function () {
 5324-      var result = false;
 5325-      for (var i = 0; i < arguments.length; i++) {
 5326-        if (arguments[i]) {
 5327-          result = true;
 5328-        }
 5329-      }
 5330-      return result;
 5331-    };
 5332-
 5333-    Formula.TRUE = function () {
 5334-      return true;
 5335-    };
 5336-
 5337-    Formula.XOR = function () {
 5338-      var result = 0;
 5339-      for (var i = 0; i < arguments.length; i++) {
 5340-        if (arguments[i]) {
 5341-          result++;
 5342-        }
 5343-      }
 5344-      return (Math.floor(Math.abs(result)) & 1) ? true : false;
 5345-    };
 5346-
 5347-
 5348-    // Lookup and reference functions
 5349-
 5350-    Formula.REFERENCE = function (context, reference) {
 5351-      try {
 5352-        var path = reference.split('.'),
 5353-          result = context;
 5354-        _(path).forEach(function (step) {
 5355-          if (step[step.length - 1] === ']') {
 5356-            var opening = step.indexOf('[');
 5357-            var index = step.substring(opening + 1, step.length - 1);
 5358-            result = result[step.substring(0, opening)][index];
 5359-          } else {
 5360-            result = result[step];
 5361-          }
 5362-        });
 5363-        return result;
 5364-      } catch (error) {
 5365-        return;
 5366-      }
 5367-    };
 5368-
 5369-
 5370-    // Math functions
 5371-
 5372-    Formula.ABS = function (number) {
 5373-      return Math.abs(number);
 5374-    };
 5375-
 5376-    Formula.ACOS = function (number) {
 5377-      return Math.acos(number);
 5378-    };
 5379-
 5380-    Formula.ACOSH = function (number) {
 5381-      return Math.log(number + Math.sqrt(number * number - 1));
 5382-    };
 5383-
 5384-    Formula.ACOT = function (number) {
 5385-      return Math.atan(1 / number);
 5386-    };
 5387-
 5388-    Formula.ACOTH = function (number) {
 5389-      return 0.5 * Math.log((number + 1) / (number - 1));
 5390-    };
 5391-
 5392-    Formula.AGGREGATE = function (function_code) {
 5393-      var result = [];
 5394-      for (var i = 2; i < arguments.length; i++) {
 5395-        switch (function_code) {
 5396-          case 1:
 5397-            result[i - 2] = Formula.AVERAGE(arguments[i]);
 5398-            break;
 5399-          case 2:
 5400-            result[i - 2] = Formula.COUNT(arguments[i]);
 5401-            break;
 5402-          case 3:
 5403-            result[i - 2] = Formula.COUNTA(arguments[i]);
 5404-            break;
 5405-          case 4:
 5406-            result[i - 2] = Formula.MAX(arguments[i]);
 5407-            break;
 5408-          case 5:
 5409-            result[i - 2] = Formula.MIN(arguments[i]);
 5410-            break;
 5411-          case 6:
 5412-            result[i - 2] = Formula.PRODUCT(arguments[i]);
 5413-            break;
 5414-          case 7:
 5415-            result[i - 2] = Formula.STDEVS(arguments[i]);
 5416-            break;
 5417-          case 8:
 5418-            result[i - 2] = Formula.STDEVP(arguments[i]);
 5419-            break;
 5420-          case 9:
 5421-            result[i - 2] = Formula.SUM(arguments[i]);
 5422-            break;
 5423-          case 10:
 5424-            result[i - 2] = Formula.VARS(arguments[i]);
 5425-            break;
 5426-          case 11:
 5427-            result[i - 2] = Formula.VARP(arguments[i]);
 5428-            break;
 5429-          case 12:
 5430-            result[i - 2] = Formula.MEDIAN(arguments[i]);
 5431-            break;
 5432-          case 13:
 5433-            result[i - 2] = Formula.MODESNGL(arguments[i]);
 5434-            break;
 5435-          case 14:
 5436-            result[i - 2] = Formula.LARGE(arguments[i]);
 5437-            break;
 5438-          case 15:
 5439-            result[i - 2] = Formula.SMALL(arguments[i]);
 5440-            break;
 5441-          case 16:
 5442-            result[i - 2] = Formula.PERCENTILEINC(arguments[i]);
 5443-            break;
 5444-          case 17:
 5445-            result[i - 2] = Formula.QUARTILEINC(arguments[i]);
 5446-            break;
 5447-          case 18:
 5448-            result[i - 2] = Formula.PERCENTILEEXC(arguments[i]);
 5449-            break;
 5450-          case 19:
 5451-            result[i - 2] = Formula.QUARTILEEXC(arguments[i]);
 5452-            break;
 5453-        }
 5454-      }
 5455-      return result;
 5456-    };
 5457-
 5458-    Formula.ARABIC = function (text) {
 5459-      // Credits: Rafa? Kukawski
 5460-      if (!/^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/.test(text)) {
 5461-        throw new Error('Incorrect roman number');
 5462-      }
 5463-      var r = 0;
 5464-      text.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g, function (i) {
 5465-        r += {M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1}[i];
 5466-      });
 5467-      return r;
 5468-    };
 5469-
 5470-    Formula.ASIN = function (number) {
 5471-      return Math.asin(number);
 5472-    };
 5473-
 5474-    Formula.ASINH = function (number) {
 5475-      return Math.log(number + Math.sqrt(number * number + 1));
 5476-    };
 5477-
 5478-    Formula.ATAN = function (number) {
 5479-      return Math.atan(number);
 5480-    };
 5481-
 5482-    Formula.ATAN2 = function (number_x, number_y) {
 5483-      return Math.atan2(number_x, number_y);
 5484-    };
 5485-
 5486-    Formula.ATANH = function (number) {
 5487-      return Math.log((1 + number) / (1 - number)) / 2;
 5488-    };
 5489-
 5490-    Formula.BASE = function (number, radix, min_length) {
 5491-      min_length = (typeof min_length === 'undefined') ? 0 : min_length;
 5492-      var result = number.toString(radix);
 5493-      return new Array(Math.max(min_length + 1 - result.length, 0)).join('0') + result;
 5494-    };
 5495-
 5496-    Formula.CEILING = function (number, significance, mode) {
 5497-      if (significance === 0) {
 5498-        return 0;
 5499-      }
 5500-      significance = (typeof significance === 'undefined') ? 1 : Math.abs(significance);
 5501-      mode = (typeof mode === 'undefined') ? 0 : mode;
 5502-      var precision = -Math.floor(Math.log(significance) / Math.log(10));
 5503-      if (number >= 0) {
 5504-        return Formula.ROUND(Math.ceil(number / significance) * significance, precision);
 5505-      } else {
 5506-        if (mode === 0) {
 5507-          return -Formula.ROUND(Math.floor(Math.abs(number) / significance) * significance, precision);
 5508-        } else {
 5509-          return -Formula.ROUND(Math.ceil(Math.abs(number) / significance) * significance, precision);
 5510-        }
 5511-      }
 5512-    };
 5513-
 5514-    Formula.CEILINGMATH = Formula.CEILING;
 5515-
 5516-    Formula.CEILINGPRECISE = Formula.CEILING;
 5517-
 5518-    Formula.COMBIN = function (number, number_chosen) {
 5519-      return Formula.FACT(number) / (Formula.FACT(number_chosen) * Formula.FACT(number - number_chosen));
 5520-    };
 5521-
 5522-    Formula.COMBINA = function (number, number_chosen) {
 5523-      return (number === 0 && number_chosen === 0) ? 1 : Formula.COMBIN(number + number_chosen - 1, number - 1);
 5524-    };
 5525-
 5526-    Formula.COS = Math.cos;
 5527-
 5528-    Formula.COSH = function (number) {
 5529-      return (Math.exp(number) + Math.exp(-number)) / 2;
 5530-    };
 5531-
 5532-    Formula.COT = function (number) {
 5533-      return 1 / Math.tan(number);
 5534-    };
 5535-
 5536-    Formula.COTH = function (number) {
 5537-      var e2 = Math.exp(2 * number);
 5538-      return (e2 + 1) / (e2 - 1);
 5539-    };
 5540-
 5541-    Formula.CSC = function (number) {
 5542-      return 1 / Math.sin(number);
 5543-    };
 5544-
 5545-    Formula.CSCH = function (number) {
 5546-      return 2 / (Math.exp(number) - Math.exp(-number));
 5547-    };
 5548-
 5549-    Formula.DECIMAL = function (number, radix) {
 5550-      return parseInt(number, radix);
 5551-    };
 5552-
 5553-    Formula.DEGREES = function (number) {
 5554-      return number * 180 / Math.PI;
 5555-    };
 5556-
 5557-    Formula.EVEN = function (number) {
 5558-      return Formula.CEILING(number, -2, -1);
 5559-    };
 5560-
 5561-    Formula.EXP = Math.exp;
 5562-
 5563-    Formula.FACT = function (number) {
 5564-      var n = Math.floor(number);
 5565-      if (n === 0 || n === 1) {
 5566-        return 1;
 5567-      } else if (MEMOIZED_FACT[n] > 0) {
 5568-        return MEMOIZED_FACT[n];
 5569-      } else {
 5570-        MEMOIZED_FACT[n] = Formula.FACT(n - 1) * n;
 5571-        return MEMOIZED_FACT[n];
 5572-      }
 5573-    };
 5574-
 5575-    Formula.FACTDOUBLE = function (number) {
 5576-      var n = Math.floor(number);
 5577-      if (n <= 0) {
 5578-        return 1;
 5579-      } else {
 5580-        return n * Formula.FACTDOUBLE(n - 2);
 5581-      }
 5582-    };
 5583-
 5584-    Formula.FLOOR = function (number, significance, mode) {
 5585-      if (significance === 0) {
 5586-        return 0;
 5587-      }
 5588-
 5589-      significance = significance ? Math.abs(significance) : 1;
 5590-      var precision = -Math.floor(Math.log(significance) / Math.log(10));
 5591-      if (number >= 0) {
 5592-        return Formula.ROUND(Math.floor(number / significance) * significance, precision);
 5593-      } else if (mode === 0 || typeof mode === 'undefined') {
 5594-        return -Formula.ROUND(Math.ceil(Math.abs(number) / significance) * significance, precision);
 5595-      }
 5596-      return -Formula.ROUND(Math.floor(Math.abs(number) / significance) * significance, precision);
 5597-    };
 5598-
 5599-    Formula.FLOORMATH = Formula.FLOOR;
 5600-
 5601-    Formula.FLOORPRECISE = function(number, significance) {
 5602-      if (significance === 0) {
 5603-        return 0;
 5604-      }
 5605-
 5606-      significance = significance ? Math.abs(significance) : 1;
 5607-      var precision = -Math.floor(Math.log(significance) / Math.log(10));
 5608-      if (number >= 0) {
 5609-        return Formula.ROUND(Math.round(number / significance) * significance, precision);
 5610-      }
 5611-      return -Formula.ROUND(Math.ceil(Math.abs(number) / significance) * significance, precision);
 5612-    };
 5613-
 5614-    Formula.GCD = function () {
 5615-      // Credits: Andrew Pociu
 5616-      for (var r, a, i = arguments.length - 1, result = arguments[i]; i;) {
 5617-        for (a = arguments[--i]; (r = a % result); a = result, result = r) {
 5618-          //empty
 5619-        }
 5620-      }
 5621-      return result;
 5622-    };
 5623-
 5624-    Formula.INT = function (number) {
 5625-      return Math.floor(number);
 5626-    };
 5627-
 5628-    Formula.ISEVEN = function (number) {
 5629-      return (Math.floor(Math.abs(number)) & 1) ? false : true;
 5630-    };
 5631-
 5632-    Formula.ISOCEILING = Formula.CEILING;
 5633-
 5634-    Formula.ISODD = function (number) {
 5635-      return (Math.floor(Math.abs(number)) & 1) ? true : false;
 5636-    };
 5637-
 5638-    Formula.LCM = function () {
 5639-      // Credits: Jonas Raoni Soares Silva
 5640-      var o = Formula.ARGSTOARRAY(arguments);
 5641-      for (var i, j, n, d, r = 1; (n = o.pop()) !== undefined;) {
 5642-        while (n > 1) {
 5643-          if (n % 2) {
 5644-            for (i = 3, j = Math.floor(Math.sqrt(n)); i <= j && n % i; i += 2) {
 5645-              //empty
 5646-            }
 5647-            d = (i <= j) ? i : n;
 5648-          } else {
 5649-            d = 2;
 5650-          }
 5651-          for (n /= d, r *= d, i = o.length; i; (o[--i] % d) === 0 && (o[i] /= d) === 1 && o.splice(i, 1)) {
 5652-            //empty
 5653-          }
 5654-        }
 5655-      }
 5656-      return r;
 5657-    };
 5658-
 5659-    Formula.LN = function (number) {
 5660-      return Math.log(number);
 5661-    };
 5662-
 5663-    Formula.LOG = function (number, base) {
 5664-      base = (typeof base === 'undefined') ? 10 : base;
 5665-      return Math.log(number) / Math.log(base);
 5666-    };
 5667-
 5668-    Formula.LOG10 = function (number) {
 5669-      return Math.log(number) / Math.log(10);
 5670-    };
 5671-
 5672-    Formula.MDETERM = numeric.det;
 5673-
 5674-    Formula.MINVERSE = numeric.inv;
 5675-
 5676-    Formula.MMULT = numeric.dot;
 5677-
 5678-    Formula.MOD = function (dividend, divisor) {
 5679-      var modulus = Math.abs(dividend % divisor);
 5680-      return (divisor > 0) ? modulus : -modulus;
 5681-    };
 5682-
 5683-    Formula.MROUND = function (number, multiple) {
 5684-      if (number * multiple < 0) {
 5685-        throw new Error('Number and multiple must have the same sign.');
 5686-      }
 5687-
 5688-      return Math.round(number / multiple) * multiple;
 5689-    };
 5690-
 5691-    Formula.MULTINOMIAL = function () {
 5692-      var sum = 0;
 5693-      var divisor = 1;
 5694-      for (var i = 0; i < arguments.length; i++) {
 5695-        sum += arguments[i];
 5696-        divisor *= Formula.FACT(arguments[i]);
 5697-      }
 5698-      return Formula.FACT(sum) / divisor;
 5699-    };
 5700-
 5701-    Formula.MUNIT = numeric.identity;
 5702-
 5703-    Formula.ODD = function (number) {
 5704-      var temp = Math.ceil(Math.abs(number));
 5705-      temp = (temp & 1) ? temp : temp + 1;
 5706-      return (number > 0) ? temp : -temp;
 5707-    };
 5708-
 5709-    Formula.E = function () {
 5710-      return Math.E;
 5711-    };
 5712-
 5713-    Formula.PI = function () {
 5714-      return Math.PI;
 5715-    };
 5716-
 5717-    Formula.POWER = function (number, power) {
 5718-      var result = Math.pow(number, power);
 5719-      if (isNaN(result)) {
 5720-        return '#NUM!';
 5721-      }
 5722-
 5723-      return result;
 5724-    };
 5725-
 5726-    Formula.PRODUCT = function () {
 5727-      var result = 1;
 5728-      for (var i = 0; i < arguments.length; i++) {
 5729-        result *= arguments[i];
 5730-      }
 5731-      return result;
 5732-    };
 5733-
 5734-    Formula.QUOTIENT = function (numerator, denominator) {
 5735-      return (numerator / denominator).toFixed(0);
 5736-    };
 5737-
 5738-    Formula.RADIANS = function (number) {
 5739-      return number * Math.PI / 180;
 5740-    };
 5741-
 5742-    Formula.RAND = function () {
 5743-      return Math.random();
 5744-    };
 5745-
 5746-    Formula.RANDBETWEEN = function (bottom, top) {
 5747-      // Creative Commons Attribution 3.0 License
 5748-      // Copyright (c) 2012 eqcode
 5749-      return bottom + Math.ceil((top - bottom + 1) * Math.random()) - 1;
 5750-    };
 5751-
 5752-    Formula.ROUND = function (number, digits) {
 5753-      return Math.round(number * Math.pow(10, digits)) / Math.pow(10, digits);
 5754-    };
 5755-
 5756-    Formula.ROUNDDOWN = function (number, digits) {
 5757-      var sign = (number > 0) ? 1 : -1;
 5758-      return sign * (Math.floor(Math.abs(number) * Math.pow(10, digits))) / Math.pow(10, digits);
 5759-    };
 5760-
 5761-    Formula.ROUNDUP = function (number, digits) {
 5762-      var sign = (number > 0) ? 1 : -1;
 5763-      return sign * (Math.ceil(Math.abs(number) * Math.pow(10, digits))) / Math.pow(10, digits);
 5764-    };
 5765-
 5766-    Formula.SERIESSUM = function (x, n, m, coefficients) {
 5767-      var result = coefficients[0] * Math.pow(x, n);
 5768-      for (var i = 1; i < coefficients.length; i++) {
 5769-        result += coefficients[i] * Math.pow(x, n + i * m);
 5770-      }
 5771-      return result;
 5772-    };
 5773-
 5774-    Formula.SEC = function (number) {
 5775-      return 1 / Math.cos(number);
 5776-    };
 5777-
 5778-    Formula.SECH = function (number) {
 5779-      return 2 / (Math.exp(number) + Math.exp(-number));
 5780-    };
 5781-
 5782-    Formula.SIGN = function (number) {
 5783-      if (number < 0) {
 5784-        return -1;
 5785-      } else if (number === 0) {
 5786-        return 0;
 5787-      } else {
 5788-        return 1;
 5789-      }
 5790-    };
 5791-
 5792-    Formula.SIN = Math.sin;
 5793-
 5794-    Formula.SINH = function (number) {
 5795-      return (Math.exp(number) - Math.exp(-number)) / 2;
 5796-    };
 5797-
 5798-    Formula.SQRT = Math.sqrt;
 5799-
 5800-    Formula.SQRTPI = function (number) {
 5801-      return Math.sqrt(number * Math.PI);
 5802-    };
 5803-
 5804-    Formula.SUBTOTAL = function (function_code) {
 5805-      var result = [];
 5806-      for (var i = 1; i < arguments.length; i++) {
 5807-        switch (function_code) {
 5808-          case 1:
 5809-            result[i - 1] = Formula.AVERAGE(arguments[i]);
 5810-            break;
 5811-          case 2:
 5812-            result[i - 1] = Formula.COUNT(arguments[i]);
 5813-            break;
 5814-          case 3:
 5815-            result[i - 1] = Formula.COUNTA(arguments[i]);
 5816-            break;
 5817-          case 4:
 5818-            result[i - 1] = Formula.MAX(arguments[i]);
 5819-            break;
 5820-          case 5:
 5821-            result[i - 1] = Formula.MIN(arguments[i]);
 5822-            break;
 5823-          case 6:
 5824-            result[i - 1] = Formula.PRODUCT(arguments[i]);
 5825-            break;
 5826-          case 7:
 5827-            result[i - 1] = Formula.STDEV(arguments[i]);
 5828-            break;
 5829-          case 8:
 5830-            result[i - 1] = Formula.STDEVP(arguments[i]);
 5831-            break;
 5832-          case 9:
 5833-            result[i - 1] = Formula.SUM(arguments[i]);
 5834-            break;
 5835-          case 10:
 5836-            result[i - 1] = Formula.VAR(arguments[i]);
 5837-            break;
 5838-          case 11:
 5839-            result[i - 1] = Formula.VARP(arguments[i]);
 5840-            break;
 5841-        }
 5842-      }
 5843-      return result;
 5844-    };
 5845-
 5846-    Formula.SUM = function () {
 5847-      var numbers = Formula.FLATTEN(arguments);
 5848-      var result = 0;
 5849-      for (var i = 0; i < numbers.length; i++) {
 5850-        if (numbers[i] instanceof Array) {
 5851-          for (var j = 0; j < numbers[i].length; j++) {
 5852-            result += (Formula.ISNUMBER(numbers[i][j])) ? numbers[i][j] : 0;
 5853-          }
 5854-        } else {
 5855-          result += (Formula.ISNUMBER(numbers[i])) ? numbers[i] : 0;
 5856-        }
 5857-      }
 5858-
 5859-      return result;
 5860-    };
 5861-
 5862-    Formula.SUMIF = function (range, criteria) {
 5863-      range = Formula.FLATTEN(range);
 5864-      var result = 0;
 5865-      for (var i = 0; i < range.length; i++) {
 5866-        result += (eval(range[i] + criteria)) ? range[i] : 0;
 5867-      }
 5868-      return result;
 5869-    };
 5870-
 5871-    Formula.SUMIFS = function () {
 5872-      var criteria = (arguments.length - 1) / 2;
 5873-      var range = arguments[0];
 5874-      var result = 0;
 5875-      for (var i = 0; i < range.length; i++) {
 5876-        var fit = true;
 5877-        for (var j = 0; j < criteria; j++) {
 5878-          if (!eval(arguments[2 * j + 1][i] + arguments[2 * j + 2])) {
 5879-            fit = false;
 5880-          }
 5881-        }
 5882-        result += (fit) ? range[i] : 0;
 5883-      }
 5884-      return result;
 5885-
 5886-//      var args = Formula.ARGSTOARRAY(arguments);
 5887-//      var range = Formula.FLATTEN(args.shift());
 5888-//      var criteria = args;
 5889-//
 5890-//      var n_range_elements = range.length;
 5891-//      var n_criterias = criteria.length;
 5892-//
 5893-//      var result = 0;
 5894-//      for (var i = 0; i < n_range_elements; i++) {
 5895-//        var el = range[i];
 5896-//        var condition = '';
 5897-//        for (var c = 0; c < n_criterias; c++) {
 5898-//          condition += el+criteria[c];
 5899-//          if (c !== n_criterias - 1) {
 5900-//            condition += '&&';
 5901-//          }
 5902-//        }
 5903-//        if (eval(condition)) {
 5904-//          result += el;
 5905-//        }
 5906-//      }
 5907-//      return result;
 5908-    };
 5909-
 5910-    Formula.SUMPRODUCT = function () {
 5911-      var arrays = arguments.length + 1;
 5912-      var result = 0;
 5913-      for (var i = 0; i < arguments[0].length; i++) {
 5914-        for (var j = 0; j < arguments[0][i].length; j++) {
 5915-          var product = 1;
 5916-          for (var k = 1; k < arrays; k++) {
 5917-            product *= arguments[k - 1][i][j];
 5918-          }
 5919-          result += product;
 5920-        }
 5921-      }
 5922-      return result;
 5923-    };
 5924-
 5925-    Formula.SUMSQ = function () {
 5926-      var numbers = Formula.FLATTEN(arguments);
 5927-      var result = 0;
 5928-      for (var i = 0; i < numbers.length; i++) {
 5929-        result += (Formula.ISNUMBER(numbers[i])) ? numbers[i] * numbers[i] : 0;
 5930-      }
 5931-      return result;
 5932-    };
 5933-
 5934-    Formula.SUMX2MY2 = function (array_x, array_y) {
 5935-      var result = 0;
 5936-      array_x = Formula.FLATTEN(array_x);
 5937-      array_y = Formula.FLATTEN(array_y);
 5938-      for (var i = 0; i < array_x.length; i++) {
 5939-        result += array_x[i] * array_x[i] - array_y[i] * array_y[i];
 5940-      }
 5941-      return result;
 5942-    };
 5943-
 5944-    Formula.SUMX2PY2 = function (array_x, array_y) {
 5945-      var result = 0;
 5946-      array_x = Formula.FLATTEN(array_x);
 5947-      array_y = Formula.FLATTEN(array_y);
 5948-      for (var i = 0; i < array_x.length; i++) {
 5949-        result += array_x[i] * array_x[i] + array_y[i] * array_y[i];
 5950-      }
 5951-      return result;
 5952-    };
 5953-
 5954-    Formula.SUMXMY2 = function (array_x, array_y) {
 5955-      var result = 0;
 5956-      array_x = Formula.FLATTEN(array_x);
 5957-      array_y = Formula.FLATTEN(array_y);
 5958-      for (var i = 0; i < array_x.length; i++) {
 5959-        result += Math.pow(array_x[i] - array_y[i], 2);
 5960-      }
 5961-      return result;
 5962-    };
 5963-
 5964-    Formula.TAN = function (number) {
 5965-      return Math.tan(number);
 5966-    };
 5967-
 5968-    Formula.TANH = function (number) {
 5969-      var e2 = Math.exp(2 * number);
 5970-      return (e2 - 1) / (e2 + 1);
 5971-    };
 5972-
 5973-    Formula.TRUNC = function (number, digits) {
 5974-      digits = (typeof digits === 'undefined') ? 0 : digits;
 5975-      var sign = (number > 0) ? 1 : -1;
 5976-      return sign * (Math.floor(Math.abs(number) * Math.pow(10, digits))) / Math.pow(10, digits);
 5977-    };
 5978-
 5979-
 5980-    // Statistical functions
 5981-    Formula.AVEDEV = function () {
 5982-      var range = Formula.FLATTEN(arguments);
 5983-      return jStat.sum(jStat(range).subtract(jStat.mean(range)).abs()[0]) / range.length;
 5984-    };
 5985-
 5986-    Formula.AVERAGE = function () {
 5987-      var range = Formula.NUMBERS(Formula.FLATTEN(arguments));
 5988-      var n = range.length;
 5989-      var sum = 0;
 5990-      var count = 0;
 5991-      for (var i = 0; i < n; i++) {
 5992-        sum += range[i];
 5993-        count += 1;
 5994-      }
 5995-      return sum / count;
 5996-    };
 5997-
 5998-    Formula.AVERAGEA = function () {
 5999-      var range = Formula.FLATTEN(arguments);
 6000-      var n = range.length;
 6001-      var sum = 0;
 6002-      var count = 0;
 6003-      for (var i = 0; i < n; i++) {
 6004-        var el = range[i];
 6005-        if (typeof el === 'number') {
 6006-          sum += el;
 6007-        }
 6008-        if (el === true) {
 6009-          sum++;
 6010-        }
 6011-        if (el !== null) {
 6012-          count++;
 6013-        }
 6014-      }
 6015-      return sum / count;
 6016-    };
 6017-
 6018-    Formula.AVERAGEIF = function (range, criteria, average_range) {
 6019-      average_range = average_range || range;
 6020-      range = Formula.FLATTEN(range);
 6021-      average_range = Formula.FLATTEN(average_range);
 6022-      var average_count = 0;
 6023-      var result = 0;
 6024-      for (var i = 0; i < range.length; i++) {
 6025-        if (eval(range[i] + criteria)) {
 6026-          result += average_range[i];
 6027-          average_count++;
 6028-        }
 6029-      }
 6030-      return result / average_count;
 6031-    };
 6032-
 6033-    Formula.AVERAGEIFS = function () {
 6034-      // Does not work with multi dimensional ranges yet!
 6035-      //http://office.microsoft.com/en-001/excel-help/averageifs-function-HA010047493.aspx
 6036-      var args = Formula.ARGSTOARRAY(arguments);
 6037-      var criteria = (args.length - 1) / 2;
 6038-      var range = Formula.FLATTEN(args[0]);
 6039-      var count = 0;
 6040-      var result = 0;
 6041-      for (var i = 0; i < range.length; i++) {
 6042-        var condition = '';
 6043-        for (var j = 0; j < criteria; j++) {
 6044-          condition += args[2 * j + 1][i] + args[2 * j + 2];
 6045-          if (j !== criteria - 1) {
 6046-            condition += '&&';
 6047-          }
 6048-        }
 6049-        if (eval(condition)) {
 6050-          result += range[i];
 6051-          count++;
 6052-        }
 6053-      }
 6054-
 6055-      var average = result / count;
 6056-      if (isNaN(average)) {
 6057-        return 0;
 6058-      } else {
 6059-        return average;
 6060-      }
 6061-    };
 6062-
 6063-    Formula.BETADIST = function (x, alpha, beta, cumulative, A, B) {
 6064-      A = (typeof A === 'undefined') ? 0 : A;
 6065-      B = (typeof B === 'undefined') ? 1 : B;
 6066-      x = (x - A) / (B - A);
 6067-      return (cumulative) ? jStat.beta.cdf(x, alpha, beta) : jStat.beta.pdf(x, alpha, beta);
 6068-    };
 6069-
 6070-    Formula.BETAINV = function (probability, alpha, beta, A, B) {
 6071-      A = (typeof A === 'undefined') ? 0 : A;
 6072-      B = (typeof B === 'undefined') ? 1 : B;
 6073-      return jStat.beta.inv(probability, alpha, beta) * (B - A) + A;
 6074-    };
 6075-
 6076-    Formula.BINOMDIST = function (successes, trials, probability, cumulative) {
 6077-      return (cumulative) ? jStat.binomial.cdf(successes, trials, probability) : jStat.binomial.pdf(successes, trials, probability);
 6078-    };
 6079-
 6080-    Formula.BINOMDISTRANGE = function (trials, probability, successes, successes2) {
 6081-      successes2 = (typeof successes2 === 'undefined') ? successes : successes2;
 6082-      var result = 0;
 6083-      for (var i = successes; i <= successes2; i++) {
 6084-        result += Formula.COMBIN(trials, i) * Math.pow(probability, i) * Math.pow(1 - probability, trials - i);
 6085-      }
 6086-      return result;
 6087-    };
 6088-
 6089-    Formula.BINOMINV = function (trials, probability, alpha) {
 6090-      var x = 0;
 6091-      while (x <= trials) {
 6092-        if (jStat.binomial.cdf(x, trials, probability) >= alpha) {
 6093-          return x;
 6094-        }
 6095-        x++;
 6096-      }
 6097-    };
 6098-
 6099-    Formula.CHISQDIST = function (x, k, cumulative) {
 6100-      return (cumulative) ? jStat.chisquare.cdf(x, k) : jStat.chisquare.pdf(x, k);
 6101-    };
 6102-
 6103-    Formula.CHISQDISTRT = function () {
 6104-      return;
 6105-    };
 6106-
 6107-    Formula.CHISQINV = function (probability, k) {
 6108-      return jStat.chisquare.inv(probability, k);
 6109-    };
 6110-
 6111-    Formula.CHISQINVRT = function () {
 6112-      return;
 6113-    };
 6114-
 6115-    Formula.CHISQTEST = function () {
 6116-      return;
 6117-    };
 6118-
 6119-    Formula.CONFIDENCENORM = function (alpha, sd, n) {
 6120-      return jStat.normalci(1, alpha, sd, n)[1] - 1;
 6121-    };
 6122-
 6123-    Formula.CONFIDENCET = function (alpha, sd, n) {
 6124-      return jStat.tci(1, alpha, sd, n)[1] - 1;
 6125-    };
 6126-
 6127-    Formula.CORREL = function () {
 6128-      return jStat.corrcoeff.apply(this, arguments);
 6129-    };
 6130-
 6131-    Formula.COUNT = function () {
 6132-      var numbers = Formula.NUMBERS(Formula.FLATTEN(arguments));
 6133-      return numbers.length;
 6134-    };
 6135-
 6136-    Formula.COUNTA = function () {
 6137-      var range = Formula.FLATTEN(arguments);
 6138-      return range.length - Formula.COUNTBLANK(range);
 6139-    };
 6140-
 6141-    Formula.COUNTBLANK = function () {
 6142-      var range = Formula.FLATTEN(arguments);
 6143-      var blanks = 0;
 6144-      var element;
 6145-      for (var i = 0; i < range.length; i++) {
 6146-        element = range[i];
 6147-        if (element === null || element === '' || !element) {
 6148-          blanks++;
 6149-        }
 6150-      }
 6151-      return blanks;
 6152-    };
 6153-
 6154-    Formula.COUNTIF = function (range, criteria) {
 6155-      range = Formula.FLATTEN(range);
 6156-      var matches = 0;
 6157-      for (var i = 0; i < range.length; i++) {
 6158-        if (range[i].match(new RegExp(criteria))) {
 6159-          matches++;
 6160-        }
 6161-      }
 6162-      return matches;
 6163-//      if (!/[<>=!]/.test(criteria)) {
 6164-//        criteria = '=="'+criteria+'"';
 6165-//      }
 6166-//      var matches = 0;
 6167-//      for (var i = 0; i < range.length; i++) {
 6168-//        if (typeof range[i] !== 'string') {
 6169-//          if (eval(range[i]+criteria)) {
 6170-//            matches++;
 6171-//          }
 6172-//        } else {
 6173-//          if (eval('"'+range[i]+'"'+criteria)) {
 6174-//            matches++;
 6175-//          }
 6176-//        }
 6177-//      }
 6178-//      return matches;
 6179-    };
 6180-
 6181-    Formula.COUNTIFS = function () {
 6182-      var criteria = (arguments.length - 1) / 2;
 6183-      var range = arguments[0];
 6184-      var result = 0;
 6185-      for (var i = 0; i < range.length; i++) {
 6186-        var fit = true;
 6187-        for (var j = 0; j < criteria; j++) {
 6188-          if (!eval(arguments[2 * j + 1][i] + arguments[2 * j + 2])) {
 6189-            fit = false;
 6190-          }
 6191-        }
 6192-        result += (fit) ? 1 : 0;
 6193-      }
 6194-      return result;
 6195-
 6196-//      var args = Formula.ARGSTOARRAY(arguments);
 6197-//      var results = new Array(Formula.FLATTEN(args[0]).length);
 6198-//      for (var i = 0; i < results.length; i++) {
 6199-//        results[i] = true;
 6200-//      }
 6201-//      for (i = 0; i < args.length; i += 2) {
 6202-//        var range = Formula.FLATTEN(args[i]);
 6203-//        var criteria = args[i + 1];
 6204-//        if (!/[<>=!]/.test(criteria)) {
 6205-//          criteria = '=="'+criteria+'"';
 6206-//        }
 6207-//        for (var j = 0; j < range.length; j++) {
 6208-//          if (typeof range[j] !== 'string') {
 6209-//            results[j] = results[j] && eval(range[j]+criteria);
 6210-//          } else {
 6211-//            results[j] = results[j] && eval('"'+range[j]+'"'+criteria);
 6212-//          }
 6213-//        }
 6214-//      }
 6215-//      var result = 0;
 6216-//      for (i = 0; i < results.length; i++) {
 6217-//        if (results[i]) {
 6218-//          result++;
 6219-//        }
 6220-//      }
 6221-//      return result;
 6222-    };
 6223-
 6224-    Formula.COUNTUNIQUE = function () {
 6225-      return _.uniq(Formula.FLATTEN(arguments)).length;
 6226-    };
 6227-
 6228-    Formula.COVARIANCEP = function (array1, array2) {
 6229-      array1 = Formula.FLATTEN(array1);
 6230-      array2 = Formula.FLATTEN(array2);
 6231-
 6232-      var mean1 = jStat.mean(array1);
 6233-      var mean2 = jStat.mean(array2);
 6234-      var result = 0;
 6235-      var n = array1.length;
 6236-      for (var i = 0; i < n; i++) {
 6237-        result += (array1[i] - mean1) * (array2[i] - mean2);
 6238-      }
 6239-      return result / n;
 6240-    };
 6241-
 6242-    Formula.COVARIANCES = function () {
 6243-      return jStat.covariance.apply(this, simplifyArguments(arguments));
 6244-    };
 6245-
 6246-    Formula.DEVSQ = function () {
 6247-      var range = Formula.ARGSCONCAT(arguments);
 6248-      var mean = jStat.mean(range);
 6249-      var result = 0;
 6250-      for (var i = 0; i < range.length; i++) {
 6251-        result += Math.pow((range[i] - mean), 2);
 6252-      }
 6253-      return result;
 6254-    };
 6255-
 6256-    Formula.EXPONDIST = function (x, lambda, cumulative) {
 6257-      return (cumulative) ? jStat.exponential.cdf(x, lambda) : jStat.exponential.pdf(x, lambda);
 6258-    };
 6259-
 6260-    Formula.FDIST = function (x, d1, d2, cumulative) {
 6261-      return (cumulative) ? jStat.centralF.cdf(x, d1, d2) : jStat.centralF.pdf(x, d1, d2);
 6262-    };
 6263-
 6264-    Formula.FDISTRT = function () {
 6265-      return;
 6266-    };
 6267-
 6268-    Formula.FINV = function (probability, d1, d2) {
 6269-      if (probability <= 0.0 || probability > 1.0) {
 6270-        return '#NUM!';
 6271-      }
 6272-
 6273-      return jStat.centralF.inv(1.0 - probability, d1, d2);
 6274-    };
 6275-
 6276-    Formula.FINVRT = function () {
 6277-      return;
 6278-    };
 6279-
 6280-    Formula.FTEST = function () {
 6281-      return;
 6282-    };
 6283-
 6284-    Formula.FISHER = function (x) {
 6285-      return Math.log((1 + x) / (1 - x)) / 2;
 6286-    };
 6287-
 6288-    Formula.FISHERINV = function (y) {
 6289-      var e2y = Math.exp(2 * y);
 6290-      return (e2y - 1) / (e2y + 1);
 6291-    };
 6292-
 6293-    Formula.FORECAST = function (x, data_y, data_x) {
 6294-      data_x = Formula.FLATTEN(data_x);
 6295-      data_y = Formula.FLATTEN(data_y);
 6296-
 6297-      var xmean = jStat.mean(data_x);
 6298-      var ymean = jStat.mean(data_y);
 6299-      var n = data_x.length;
 6300-      var num = 0;
 6301-      var den = 0;
 6302-      for (var i = 0; i < n; i++) {
 6303-        num += (data_x[i] - xmean) * (data_y[i] - ymean);
 6304-        den += Math.pow(data_x[i] - xmean, 2);
 6305-      }
 6306-      var b = num / den;
 6307-      var a = ymean - b * xmean;
 6308-      return a + b * x;
 6309-    };
 6310-
 6311-    Formula.FREQUENCY = function (data, bins) {
 6312-      var n = data.length;
 6313-      var b = bins.length;
 6314-      var r = [];
 6315-      for (var i = 0; i <= b; i++) {
 6316-        r[i] = 0;
 6317-        for (var j = 0; j < n; j++) {
 6318-          if (i === 0) {
 6319-            if (data[j] <= bins[0]) {
 6320-              r[0] += 1;
 6321-            }
 6322-          } else if (i < b) {
 6323-            if (data[j] > bins[i - 1] && data[j] <= bins[i]) {
 6324-              r[i] += 1;
 6325-            }
 6326-          } else if (i === b) {
 6327-            if (data[j] > bins[b - 1]) {
 6328-              r[b] += 1;
 6329-            }
 6330-          }
 6331-        }
 6332-      }
 6333-      return r;
 6334-    };
 6335-
 6336-    Formula.GAMMA = function () {
 6337-      return jStat.gammafn.apply(this, arguments);
 6338-    };
 6339-
 6340-    //TODO
 6341-    Formula.GAMMADIST = function (/* x, alpha, beta, cumulative */) {
 6342-      /*
 6343-       var shape = alpha;
 6344-       var scale = 1 / beta;
 6345-       return (cumulative) ? jStat.gamma.cdf(x, shape, scale) : jStat.gamma.pdf(x, shape, scale);
 6346-       */
 6347-      return;
 6348-    };
 6349-
 6350-    //TODO
 6351-    Formula.GAMMAINV = function (/* probability, alpha, beta */) {
 6352-      /*
 6353-       var shape = alpha;
 6354-       var scale = 1 / beta;
 6355-       return jStat.gamma.inv(probability, shape, scale);
 6356-       */
 6357-      return;
 6358-    };
 6359-
 6360-    Formula.GAMMALN = function () {
 6361-      return jStat.gammaln.apply(this, arguments);
 6362-    };
 6363-
 6364-    //TODO
 6365-    Formula.GAMMALNPRECISE = function () {
 6366-      return;
 6367-    };
 6368-
 6369-    Formula.GAUSS = function (z) {
 6370-      return jStat.normal.cdf(z, 0, 1) - 0.5;
 6371-    };
 6372-
 6373-    Formula.GEOMEAN = function () {
 6374-      return jStat.geomean(Formula.ARGSCONCAT(arguments));
 6375-    };
 6376-
 6377-    Formula.GROWTH = function (known_y, known_x, new_x, use_const) {
 6378-      // Credits: Ilmari Karonen
 6379-
 6380-      // Default values for optional parameters:
 6381-      var i;
 6382-      if (typeof(known_x) === 'undefined') {
 6383-        known_x = [];
 6384-        for (i = 1; i <= known_y.length; i++) {
 6385-          known_x.push(i);
 6386-        }
 6387-      }
 6388-      if (typeof(new_x) === 'undefined') {
 6389-        new_x = [];
 6390-        for (i = 1; i <= known_y.length; i++) {
 6391-          new_x.push(i);
 6392-        }
 6393-      }
 6394-      if (typeof(use_const) === 'undefined') {
 6395-        use_const = true;
 6396-      }
 6397-
 6398-      // Calculate sums over the data:
 6399-      var n = known_y.length;
 6400-      var avg_x = 0;
 6401-      var avg_y = 0;
 6402-      var avg_xy = 0;
 6403-      var avg_xx = 0;
 6404-      for (i = 0; i < n; i++) {
 6405-        var x = known_x[i];
 6406-        var y = Math.log(known_y[i]);
 6407-        avg_x += x;
 6408-        avg_y += y;
 6409-        avg_xy += x * y;
 6410-        avg_xx += x * x;
 6411-      }
 6412-      avg_x /= n;
 6413-      avg_y /= n;
 6414-      avg_xy /= n;
 6415-      avg_xx /= n;
 6416-
 6417-      // Compute linear regression coefficients:
 6418-      var beta;
 6419-      var alpha;
 6420-      if (use_const) {
 6421-        beta = (avg_xy - avg_x * avg_y) / (avg_xx - avg_x * avg_x);
 6422-        alpha = avg_y - beta * avg_x;
 6423-      } else {
 6424-        beta = avg_xy / avg_xx;
 6425-        alpha = 0;
 6426-      }
 6427-
 6428-      // Compute and return result array:
 6429-      var new_y = [];
 6430-      for (i = 0; i < new_x.length; i++) {
 6431-        new_y.push(Math.exp(alpha + beta * new_x[i]));
 6432-      }
 6433-      return new_y;
 6434-    };
 6435-
 6436-    Formula.HARMEAN = function () {
 6437-      var range = Formula.ARGSCONCAT(arguments);
 6438-      var n = range.length;
 6439-      var den = 0;
 6440-      for (var i = 0; i < n; i++) {
 6441-        den += 1 / range[i];
 6442-      }
 6443-      return n / den;
 6444-    };
 6445-
 6446-    Formula.HYPGEOMDIST = function (x, n, M, N, cumulative) {
 6447-      function pdf(x, n, M, N) {
 6448-        return Formula.COMBIN(M, x) * Formula.COMBIN(N - M, n - x) / Formula.COMBIN(N, n);
 6449-      }
 6450-
 6451-      function cdf(x, n, M, N) {
 6452-        var result = 0;
 6453-        for (var i = 0; i <= x; i++) {
 6454-          result += pdf(i, n, M, N);
 6455-        }
 6456-        return result;
 6457-      }
 6458-
 6459-      return (cumulative) ? cdf(x, n, M, N) : pdf(x, n, M, N);
 6460-    };
 6461-
 6462-    Formula.INTERCEPT = function (data_y, data_x) {
 6463-      return Formula.FORECAST(0, data_y, data_x);
 6464-    };
 6465-
 6466-    Formula.KURT = function () {
 6467-      var range = Formula.ARGSCONCAT(arguments);
 6468-      var mean = jStat.mean(range);
 6469-      var n = range.length;
 6470-      var sigma = 0;
 6471-      for (var i = 0; i < n; i++) {
 6472-        sigma += Math.pow(range[i] - mean, 4);
 6473-      }
 6474-      sigma = sigma / Math.pow(jStat.stdev(range, true), 4);
 6475-      return ((n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3))) * sigma - 3 * (n - 1) * (n - 1) / ((n - 2) * (n - 3));
 6476-    };
 6477-
 6478-    Formula.LARGE = function (array, k) {
 6479-      return array.sort(function (a, b) {
 6480-        return b - a;
 6481-      })[k - 1];
 6482-    };
 6483-
 6484-    Formula.LINEST = function (data_y, data_x) {
 6485-      var xmean = jStat.mean(data_x);
 6486-      var ymean = jStat.mean(data_y);
 6487-      var n = data_x.length;
 6488-      var num = 0;
 6489-      var den = 0;
 6490-      for (var i = 0; i < n; i++) {
 6491-        num += (data_x[i] - xmean) * (data_y[i] - ymean);
 6492-        den += Math.pow(data_x[i] - xmean, 2);
 6493-      }
 6494-      var m = num / den;
 6495-      var b = ymean - m * xmean;
 6496-      return [m, b];
 6497-    };
 6498-
 6499-    //TODO
 6500-    Formula.LOGEST = function () {
 6501-      return;
 6502-    };
 6503-
 6504-    Formula.LOGNORMDIST = function (x, mean, sd, cumulative) {
 6505-      return (cumulative) ? jStat.lognormal.cdf(x, mean, sd) : jStat.lognormal.pdf(x, mean, sd);
 6506-    };
 6507-
 6508-    Formula.LOGNORMINV = function (probability, mean, sd) {
 6509-      return jStat.lognormal.inv(probability, mean, sd);
 6510-    };
 6511-
 6512-    Formula.MAX = function () {
 6513-      var range = Formula.FLATTEN(arguments);
 6514-      var n = range.length;
 6515-      var max = (n > 0) ? range[0] : 0;
 6516-      for (var i = 0; i < n; i++) {
 6517-        max = (range[i] > max && (range[i] !== true) && (range[i] !== false)) ? range[i] : max;
 6518-      }
 6519-      return max;
 6520-    };
 6521-
 6522-    Formula.MAXA = function () {
 6523-      var range = Formula.FLATTEN(arguments);
 6524-      return (range.length > 0) ? Math.max.apply(Math, range) : 0;
 6525-    };
 6526-
 6527-    Formula.MEDIAN = function () {
 6528-      return jStat.median(Formula.FLATTEN(arguments));
 6529-    };
 6530-
 6531-    Formula.MIN = function () {
 6532-      var range = Formula.FLATTEN(arguments);
 6533-      var n = range.length;
 6534-      var min = (n > 0) ? range[0] : 0;
 6535-      for (var i = 0; i < n; i++) {
 6536-        min = (range[i] < min && (range[i] !== true) && (range[i] !== false)) ? range[i] : min;
 6537-      }
 6538-      return min;
 6539-    };
 6540-
 6541-    Formula.MINA = function () {
 6542-      var range = Formula.FLATTEN(arguments);
 6543-      return (range.length > 0) ? Math.min.apply(Math, range) : 0;
 6544-    };
 6545-
 6546-    Formula.MODEMULT = function () {
 6547-      // Credits: Roönaän
 6548-      var range = Formula.ARGSCONCAT(arguments),
 6549-        n = range.length,
 6550-        count = {},
 6551-        maxItems = [],
 6552-        max = 0,
 6553-        currentItem;
 6554-      for (var i = 0; i < n; i++) {
 6555-        currentItem = range[i];
 6556-        count[currentItem] = count[currentItem] ? count[currentItem] + 1 : 1;
 6557-        if (count[currentItem] > max) {
 6558-          max = count[currentItem];
 6559-          maxItems = [];
 6560-        }
 6561-        if (count[currentItem] === max) {
 6562-          maxItems[maxItems.length] = currentItem;
 6563-        }
 6564-      }
 6565-      return maxItems;
 6566-    };
 6567-
 6568-    Formula.MODESNGL = function () {
 6569-      return Formula.MODEMULT(Formula.ARGSCONCAT(arguments)).sort(function (a, b) {
 6570-        return a - b;
 6571-      })[0];
 6572-    };
 6573-
 6574-    Formula.NEGBINOMDIST = function (k, r, p, cumulative) {
 6575-      return (cumulative) ? jStat.negbin.cdf(k, r, p) : jStat.negbin.pdf(k, r, p);
 6576-    };
 6577-
 6578-    Formula.NORMDIST = function (x, mean, sd, cumulative) {
 6579-      // Check parameters
 6580-      if (isNaN(x) || isNaN(mean) || isNaN(sd)) {
 6581-        return '#VALUE!';
 6582-      }
 6583-      if (sd <= 0) {
 6584-        return '#NUM!';
 6585-      }
 6586-
 6587-      // Return normal distribution computed by jStat [http://jstat.org]
 6588-      return (cumulative) ? jStat.normal.cdf(x, mean, sd) : jStat.normal.pdf(x, mean, sd);
 6589-    };
 6590-
 6591-    Formula.NORMINV = function (probability, mean, sd) {
 6592-      return jStat.normal.inv(probability, mean, sd);
 6593-    };
 6594-
 6595-    Formula.NORMSDIST = function (z, cumulative) {
 6596-      return (cumulative) ? jStat.normal.cdf(z, 0, 1) : jStat.normal.pdf(z, 0, 1);
 6597-    };
 6598-
 6599-    Formula.NORMSINV = function (probability) {
 6600-      return jStat.normal.inv(probability, 0, 1);
 6601-    };
 6602-
 6603-    Formula.PEARSON = function (data_x, data_y) {
 6604-      var xmean = jStat.mean(data_x);
 6605-      var ymean = jStat.mean(data_y);
 6606-      var n = data_x.length;
 6607-      var num = 0;
 6608-      var den1 = 0;
 6609-      var den2 = 0;
 6610-      for (var i = 0; i < n; i++) {
 6611-        num += (data_x[i] - xmean) * (data_y[i] - ymean);
 6612-        den1 += Math.pow(data_x[i] - xmean, 2);
 6613-        den2 += Math.pow(data_y[i] - ymean, 2);
 6614-      }
 6615-      return num / Math.sqrt(den1 * den2);
 6616-    };
 6617-
 6618-    Formula.PERCENTILEEXC = function (array, k) {
 6619-      array = array.sort(function (a, b) {
 6620-        {
 6621-          return a - b;
 6622-        }
 6623-      });
 6624-      var n = array.length;
 6625-      if (k < 1 / (n + 1) || k > 1 - 1 / (n + 1)) {
 6626-        return '#NUM!';
 6627-      }
 6628-      var l = k * (n + 1) - 1;
 6629-      var fl = Math.floor(l);
 6630-      return Formula.CLEANFLOAT((l === fl) ? array[l] : array[fl] + (l - fl) * (array[fl + 1] - array[fl]));
 6631-    };
 6632-
 6633-    Formula.PERCENTILEINC = function (array, k) {
 6634-      array = array.sort(function (a, b) {
 6635-        return a - b;
 6636-      });
 6637-      var n = array.length;
 6638-      var l = k * (n - 1);
 6639-      var fl = Math.floor(l);
 6640-      return Formula.CLEANFLOAT((l === fl) ? array[l] : array[fl] + (l - fl) * (array[fl + 1] - array[fl]));
 6641-    };
 6642-
 6643-    Formula.PERCENTRANKEXC = function (array, x, significance) {
 6644-      array = array.sort(function (a, b) {
 6645-        return a - b;
 6646-      });
 6647-      var uniques = _.uniq(array);
 6648-      var n = array.length;
 6649-      var m = uniques.length;
 6650-      significance = (typeof significance === 'undefined') ? 3 : significance;
 6651-      var power = Math.pow(10, significance);
 6652-      var result = 0;
 6653-      var match = false;
 6654-      var i = 0;
 6655-      while (!match && i < m) {
 6656-        if (x === uniques[i]) {
 6657-          result = (array.indexOf(uniques[i]) + 1) / (n + 1);
 6658-          match = true;
 6659-        } else if (x >= uniques[i] && (x < uniques[i + 1] || i === m - 1)) {
 6660-          result = (array.indexOf(uniques[i]) + 1 + (x - uniques[i]) / (uniques[i + 1] - uniques[i])) / (n + 1);
 6661-          match = true;
 6662-        }
 6663-        i++;
 6664-      }
 6665-      return Math.floor(result * power) / power;
 6666-    };
 6667-
 6668-    Formula.PERCENTRANKINC = function (array, x, significance) {
 6669-      array = array.sort(function (a, b) {
 6670-        return a - b;
 6671-      });
 6672-      var uniques = _.uniq(array);
 6673-      var n = array.length;
 6674-      var m = uniques.length;
 6675-      significance = (typeof significance === 'undefined') ? 3 : significance;
 6676-      var power = Math.pow(10, significance);
 6677-      var result = 0;
 6678-      var match = false;
 6679-      var i = 0;
 6680-      while (!match && i < m) {
 6681-        if (x === uniques[i]) {
 6682-          result = array.indexOf(uniques[i]) / (n - 1);
 6683-          match = true;
 6684-        } else if (x >= uniques[i] && (x < uniques[i + 1] || i === m - 1)) {
 6685-          result = (array.indexOf(uniques[i]) + (x - uniques[i]) / (uniques[i + 1] - uniques[i])) / (n - 1);
 6686-          match = true;
 6687-        }
 6688-        i++;
 6689-      }
 6690-      return Math.floor(result * power) / power;
 6691-    };
 6692-
 6693-    Formula.PERMUT = function (number, number_chosen) {
 6694-      return Formula.FACT(number) / Formula.FACT(number - number_chosen);
 6695-    };
 6696-
 6697-    Formula.PERMUTATIONA = function (number, number_chosen) {
 6698-      return Math.pow(number, number_chosen);
 6699-    };
 6700-
 6701-    Formula.PHI = function (x) {
 6702-      return Math.exp(-0.5 * x * x) / SQRT2PI;
 6703-    };
 6704-
 6705-    Formula.POISSONDIST = function (x, mean, cumulative) {
 6706-      return (cumulative) ? jStat.poisson.cdf(x, mean) : jStat.poisson.pdf(x, mean);
 6707-    };
 6708-
 6709-    Formula.PROB = function (range, probability, lower, upper) {
 6710-      if (typeof lower === 'undefined') {
 6711-        return 0;
 6712-      }
 6713-
 6714-      upper = (typeof upper === 'undefined') ? lower : upper;
 6715-      if (lower === upper) {
 6716-        return (range.indexOf(lower) >= 0) ? probability[range.indexOf(lower)] : 0;
 6717-      }
 6718-
 6719-      var sorted = range.sort(function (a, b) {
 6720-        return a - b;
 6721-      });
 6722-      var n = sorted.length;
 6723-      var result = 0;
 6724-      for (var i = 0; i < n; i++) {
 6725-        if (sorted[i] >= lower && sorted[i] <= upper) {
 6726-          result += probability[range.indexOf(sorted[i])];
 6727-        }
 6728-      }
 6729-      return result;
 6730-    };
 6731-
 6732-    Formula.QUARTILEEXC = function (range, quart) {
 6733-      switch (quart) {
 6734-        case 1:
 6735-          return Formula.PERCENTILEEXC(range, 0.25);
 6736-        case 2:
 6737-          return Formula.PERCENTILEEXC(range, 0.5);
 6738-        case 3:
 6739-          return Formula.PERCENTILEEXC(range, 0.75);
 6740-        default:
 6741-          return '#NUM!';
 6742-      }
 6743-    };
 6744-
 6745-    Formula.QUARTILEINC = function (range, quart) {
 6746-      switch (quart) {
 6747-        case 1:
 6748-          return Formula.PERCENTILEINC(range, 0.25);
 6749-        case 2:
 6750-          return Formula.PERCENTILEINC(range, 0.5);
 6751-        case 3:
 6752-          return Formula.PERCENTILEINC(range, 0.75);
 6753-        default:
 6754-          return '#NUM!';
 6755-      }
 6756-    };
 6757-
 6758-    Formula.RANKAVG = function (number, range, order) {
 6759-      order = (typeof order === 'undefined') ? false : order;
 6760-      var sort = (order) ? function (a, b) {
 6761-        return a - b;
 6762-      } : function (a, b) {
 6763-        return b - a;
 6764-      };
 6765-      range = range.sort(sort);
 6766-      var count = Formula.COUNTIN(range, number);
 6767-      return (count > 1) ? (2 * range.indexOf(number) + count + 1) / 2 : range.indexOf(number) + 1;
 6768-    };
 6769-
 6770-    Formula.RANKEQ = function (number, range, order) {
 6771-      order = (typeof order === 'undefined') ? false : order;
 6772-      var sort = (order) ? function (a, b) {
 6773-        return a - b;
 6774-      } : function (a, b) {
 6775-        return b - a;
 6776-      };
 6777-      range = range.sort(sort);
 6778-      return range.indexOf(number) + 1;
 6779-    };
 6780-
 6781-    Formula.RSQ = function (data_x, data_y) {
 6782-      return Math.pow(Formula.PEARSON(data_x, data_y), 2);
 6783-    };
 6784-
 6785-    Formula.SKEW = function () {
 6786-      var range = Formula.ARGSCONCAT(arguments);
 6787-      var mean = jStat.mean(range);
 6788-      var n = range.length;
 6789-      var sigma = 0;
 6790-      for (var i = 0; i < n; i++) {
 6791-        sigma += Math.pow(range[i] - mean, 3);
 6792-      }
 6793-      return n * sigma / ((n - 1) * (n - 2) * Math.pow(jStat.stdev(range, true), 3));
 6794-    };
 6795-
 6796-    Formula.SKEWP = function () {
 6797-      var range = Formula.ARGSCONCAT(arguments);
 6798-      var mean = jStat.mean(range);
 6799-      var n = range.length;
 6800-      var m2 = 0;
 6801-      var m3 = 0;
 6802-      for (var i = 0; i < n; i++) {
 6803-        m3 += Math.pow(range[i] - mean, 3);
 6804-        m2 += Math.pow(range[i] - mean, 2);
 6805-      }
 6806-      m3 = m3 / n;
 6807-      m2 = m2 / n;
 6808-      return m3 / Math.pow(m2, 3 / 2);
 6809-    };
 6810-
 6811-    Formula.SLOPE = function (data_y, data_x) {
 6812-      var xmean = jStat.mean(data_x);
 6813-      var ymean = jStat.mean(data_y);
 6814-      var n = data_x.length;
 6815-      var num = 0;
 6816-      var den = 0;
 6817-      for (var i = 0; i < n; i++) {
 6818-        num += (data_x[i] - xmean) * (data_y[i] - ymean);
 6819-        den += Math.pow(data_x[i] - xmean, 2);
 6820-      }
 6821-      return num / den;
 6822-    };
 6823-
 6824-    Formula.SMALL = function (array, k) {
 6825-      return array.sort(function (a, b) {
 6826-        return a - b;
 6827-      })[k - 1];
 6828-    };
 6829-
 6830-    Formula.STANDARDIZE = function (x, mean, sd) {
 6831-      return (x - mean) / sd;
 6832-    };
 6833-
 6834-    Formula.STDEVA = function () {
 6835-      var range = Formula.FLATTEN(arguments);
 6836-      var n = range.length;
 6837-      var sigma = 0;
 6838-      var mean = jStat.mean(range);
 6839-      for (var i = 0; i < n; i++) {
 6840-        sigma += Math.pow(range[i] - mean, 2);
 6841-      }
 6842-      return Math.sqrt(sigma / (n - 1));
 6843-    };
 6844-
 6845-    Formula.STDEVP = function () {
 6846-      var range = Formula.FLATTEN(arguments);
 6847-      var n = range.length;
 6848-      var sigma = 0;
 6849-      var count = 0;
 6850-      var mean = Formula.AVERAGE(range);
 6851-      for (var i = 0; i < n; i++) {
 6852-        if (range[i] !== true && range[i] !== false) {
 6853-          sigma += Math.pow(range[i] - mean, 2);
 6854-          count++;
 6855-        }
 6856-      }
 6857-      return Math.sqrt(sigma / count);
 6858-    };
 6859-
 6860-    Formula.STDEVPA = function () {
 6861-      var range = Formula.ARGSCONCAT(arguments);
 6862-      var n = range.length;
 6863-      var sigma = 0;
 6864-      var mean = jStat.mean(range);
 6865-      for (var i = 0; i < n; i++) {
 6866-        sigma += Math.pow(range[i] - mean, 2);
 6867-      }
 6868-      return Math.sqrt(sigma / n);
 6869-    };
 6870-
 6871-    Formula.STDEVS = function () {
 6872-      var range = Formula.FLATTEN(arguments);
 6873-      var n = range.length;
 6874-      var sigma = 0;
 6875-      var count = 0;
 6876-      var mean = Formula.AVERAGE(range);
 6877-      for (var i = 0; i < n; i++) {
 6878-        if (range[i] !== true && range[i] !== false) {
 6879-          sigma += Math.pow(range[i] - mean, 2);
 6880-          count++;
 6881-        }
 6882-      }
 6883-      return Math.sqrt(sigma / (count - 1));
 6884-    };
 6885-
 6886-    Formula.STEYX = function (data_y, data_x) {
 6887-      var xmean = jStat.mean(data_x);
 6888-      var ymean = jStat.mean(data_y);
 6889-      var n = data_x.length;
 6890-      var lft = 0;
 6891-      var num = 0;
 6892-      var den = 0;
 6893-      for (var i = 0; i < n; i++) {
 6894-        lft += Math.pow(data_y[i] - ymean, 2);
 6895-        num += (data_x[i] - xmean) * (data_y[i] - ymean);
 6896-        den += Math.pow(data_x[i] - xmean, 2);
 6897-      }
 6898-      return Math.sqrt((lft - num * num / den) / (n - 2));
 6899-    };
 6900-
 6901-    Formula.TDIST = function (x, df, cumulative) {
 6902-      return (cumulative) ? jStat.studentt.cdf(x, df) : jStat.studentt.pdf(x, df);
 6903-    };
 6904-
 6905-    //TODO
 6906-    Formula.TDIST2T = function () {
 6907-      return;
 6908-    };
 6909-
 6910-    //TODO
 6911-    Formula.TDISTRT = function () {
 6912-      return;
 6913-    };
 6914-
 6915-    //TODO
 6916-    Formula.TINV = function (probability, df) {
 6917-      return jStat.studentt.inv(probability, df);
 6918-    };
 6919-
 6920-    //TODO
 6921-    Formula.TINV2T = function () {
 6922-      return;
 6923-    };
 6924-
 6925-    //TODO
 6926-    Formula.TTEST = function () {
 6927-      return;
 6928-    };
 6929-
 6930-    //TODO
 6931-    Formula.TREND = function () {
 6932-      return;
 6933-    };
 6934-
 6935-    Formula.TRIMMEAN = function (range, percent) {
 6936-      range = Formula.FLATTEN(range);
 6937-      var trim = Formula.FLOOR(range.length * percent, 2) / 2;
 6938-      return jStat.mean(_.initial(_.rest(range.sort(function (a, b) {
 6939-        return a - b;
 6940-      }), trim), trim));
 6941-    };
 6942-
 6943-    Formula.VARA = function () {
 6944-      var range = Formula.FLATTEN(arguments);
 6945-      var n = range.length;
 6946-      var sigma = 0;
 6947-      var count = 0;
 6948-      var mean = Formula.AVERAGEA(range);
 6949-      for (var i = 0; i < n; i++) {
 6950-        var el = range[i];
 6951-        if (typeof el === 'number') {
 6952-          sigma += Math.pow(el - mean, 2);
 6953-        } else if (el === true) {
 6954-          sigma += Math.pow(1 - mean, 2);
 6955-        } else {
 6956-          sigma += Math.pow(0 - mean, 2);
 6957-        }
 6958-
 6959-        if (el !== null) {
 6960-          count++;
 6961-        }
 6962-      }
 6963-      return sigma / (count - 1);
 6964-    };
 6965-
 6966-    Formula.VARP = function () {
 6967-      var range = Formula.NUMBERS(Formula.FLATTEN(arguments));
 6968-      var n = range.length;
 6969-      var sigma = 0;
 6970-      var count = 0;
 6971-      var mean = Formula.AVERAGE(range);
 6972-      for (var i = 0; i < n; i++) {
 6973-        sigma += Math.pow(range[i] - mean, 2);
 6974-        count++;
 6975-      }
 6976-      return sigma / count;
 6977-    };
 6978-
 6979-    Formula.VARPA = function () {
 6980-      var range = Formula.FLATTEN(arguments);
 6981-      var n = range.length;
 6982-      var sigma = 0;
 6983-      var count = 0;
 6984-      var mean = Formula.AVERAGEA(range);
 6985-      for (var i = 0; i < n; i++) {
 6986-        var el = range[i];
 6987-        if (typeof el === 'number') {
 6988-          sigma += Math.pow(el - mean, 2);
 6989-        } else if (el === true) {
 6990-          sigma += Math.pow(1 - mean, 2);
 6991-        } else {
 6992-          sigma += Math.pow(0 - mean, 2);
 6993-        }
 6994-
 6995-        if (el !== null) {
 6996-          count++;
 6997-        }
 6998-      }
 6999-      return sigma / count;
 7000-    };
 7001-
 7002-    Formula.VARS = function () {
 7003-      var range = Formula.FLATTEN(arguments);
 7004-      var n = range.length;
 7005-      var sigma = 0;
 7006-      var count = 0;
 7007-      var mean = Formula.AVERAGE(range);
 7008-      for (var i = 0; i < n; i++) {
 7009-        if (range[i] !== true && range[i] !== false) {
 7010-          sigma += Math.pow(range[i] - mean, 2);
 7011-          count++;
 7012-        }
 7013-      }
 7014-      return sigma / (count - 1);
 7015-    };
 7016-
 7017-    Formula.WEIBULLDIST = function (x, alpha, beta, cumulative) {
 7018-      return (cumulative) ? 1 - Math.exp(-Math.pow(x / beta, alpha)) : Math.pow(x, alpha - 1) * Math.exp(-Math.pow(x / beta, alpha)) * alpha / Math.pow(beta, alpha);
 7019-    };
 7020-
 7021-    Formula.ZTEST = function (range, x, sigma) {
 7022-      var n = range.length;
 7023-      var sd = (typeof sigma === 'undefined') ? Formula.STDEVS(range) : sigma;
 7024-      return 1 - Formula.NORMSDIST((Formula.AVERAGE(range) - x) / (sd / Math.sqrt(n)), Formula.TRUE);
 7025-    };
 7026-
 7027-
 7028-    // Text functions
 7029-
 7030-    Formula.CHAR = function (number) {
 7031-      return String.fromCharCode(number);
 7032-    };
 7033-
 7034-    Formula.CLEAN = function (text) {
 7035-      return text.replace(/[\0-\x1F]/g, "");
 7036-    };
 7037-
 7038-    Formula.CODE = function (text) {
 7039-      return text.charCodeAt(0);
 7040-    };
 7041-
 7042-    Formula.CONCATENATE = function () {
 7043-      var string = '';
 7044-      for (var i = 0; i < arguments.length; i++) {
 7045-        if (arguments[i] !== null && arguments[i] !== undefined) {
 7046-          string += arguments[i];
 7047-        }
 7048-      }
 7049-
 7050-      return string;
 7051-    };
 7052-
 7053-    Formula.DOLLAR = function (number, decimals) {
 7054-      decimals = (typeof decimals === 'undefined') ? 2 : decimals;
 7055-      var format = '';
 7056-      if (decimals <= 0) {
 7057-        number = Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
 7058-        format = '($0,0)';
 7059-      } else if (decimals > 0) {
 7060-        format = '($0,0.' + new Array(decimals + 1).join('0') + ')';
 7061-      }
 7062-      return numeral(number).format(format);
 7063-    };
 7064-
 7065-    Formula.EXACT = function (text1, text2) {
 7066-      return text1 === text2;
 7067-    };
 7068-
 7069-    Formula.FIND = function (find_text, within_text, position) {
 7070-      position = (typeof position === 'undefined') ? 0 : position;
 7071-      return within_text ? within_text.indexOf(find_text, position - 1) + 1 : null;
 7072-    };
 7073-
 7074-    Formula.FIXED = function (number, decimals, no_commas) {
 7075-      decimals = (typeof decimals === 'undefined') ? 2 : decimals;
 7076-      no_commas = (typeof no_commas === 'undefined') ? false : no_commas;
 7077-      var format = no_commas ? '0' : '0,0';
 7078-      if (decimals <= 0) {
 7079-        number = Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
 7080-      } else if (decimals > 0) {
 7081-        format += '.' + new Array(decimals + 1).join('0');
 7082-      }
 7083-      return numeral(number).format(format);
 7084-    };
 7085-
 7086-    Formula.HTML2TEXT = function (value) {
 7087-      var result = '';
 7088-
 7089-      if (value) {
 7090-        if (value instanceof Array) {
 7091-          value.forEach(function (line) {
 7092-            if (result !== '') {
 7093-              result += '\n';
 7094-            }
 7095-            result += (line.replace(/<(?:.|\n)*?>/gm, ''));
 7096-          });
 7097-        } else {
 7098-          result = value.replace(/<(?:.|\n)*?>/gm, '');
 7099-        }
 7100-      }
 7101-
 7102-      return result;
 7103-    };
 7104-
 7105-    Formula.HUMANIZE = function (value) {
 7106-      if (value instanceof Date) {
 7107-        var dvalue = moment(value);
 7108-        if (dvalue.hours() || dvalue.minutes() || dvalue.seconds()) {
 7109-          return dvalue.format("dddd, MMMM Do YYYY, h:mm:ss");
 7110-        } else {
 7111-          return dvalue.format("dddd, MMMM Do YYYY");
 7112-        }
 7113-      }
 7114-
 7115-      return value;
 7116-    };
 7117-
 7118-    Formula.JOIN = function (array, separator) {
 7119-      return array.join(separator);
 7120-    };
 7121-
 7122-    Formula.LEFT = function (text, number) {
 7123-      number = (typeof number === 'undefined') ? 1 : number;
 7124-      return text ? text.substring(0, number) : null;
 7125-    };
 7126-
 7127-    Formula.LEN = function (text) {
 7128-      return text ? text.length : 0;
 7129-    };
 7130-
 7131-    Formula.LOWER = function (text) {
 7132-      return text ? text.toLowerCase() : text;
 7133-    };
 7134-
 7135-    Formula.MID = function (text, start, number) {
 7136-      return text.substring(start - 1, number);
 7137-    };
 7138-
 7139-    Formula.NUMBERVALUE = function (text, decimal_separator, group_separator) {
 7140-      decimal_separator = (typeof decimal_separator === 'undefined') ? '.' : decimal_separator;
 7141-      group_separator = (typeof group_separator === 'undefined') ? ',' : group_separator;
 7142-      return Number(text.replace(decimal_separator, '.').replace(group_separator, ''));
 7143-    };
 7144-
 7145-    Formula.NUMBERS = function () {
 7146-      var possibleNumbers = Formula.FLATTEN(arguments);
 7147-      return possibleNumbers.filter(function (el) {
 7148-        return typeof el === 'number';
 7149-      });
 7150-    };
 7151-
 7152-    Formula.PROPER = function (text) {
 7153-      if (!text) { return; }
 7154-      return text.replace(/\w\S*/g, function (txt) {
 7155-        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
 7156-      });
 7157-    };
 7158-
 7159-    Formula.REGEXEXTRACT = function (text, regular_expression) {
 7160-      var match = text.match(new RegExp(regular_expression));
 7161-      return match ? (match[match.length > 1 ? match.length - 1 : 0]) : null;
 7162-    };
 7163-
 7164-    Formula.REGEXMATCH = function (text, regular_expression, full) {
 7165-      var match = text.match(new RegExp(regular_expression));
 7166-      return full ? match : !!match;
 7167-    };
 7168-
 7169-    Formula.REGEXREPLACE = function (text, regular_expression, replacement) {
 7170-      return text.replace(new RegExp(regular_expression), replacement);
 7171-    };
 7172-
 7173-    Formula.REPLACE = function (text, position, length, new_text) {
 7174-      return text.substr(0, position - 1) + new_text + text.substr(position - 1 + length);
 7175-    };
 7176-
 7177-    Formula.REPT = function (text, number) {
 7178-      return new Array(number + 1).join(text);
 7179-    };
 7180-
 7181-    Formula.RIGHT = function (text, number) {
 7182-      number = (typeof number === 'undefined') ? 1 : number;
 7183-      return text ? text.substring(text.length - number) : null;
 7184-    };
 7185-
 7186-    Formula.ROMAN = function (number) {
 7187-      // The MIT License
 7188-      // Copyright (c) 2008 Steven Levithan
 7189-      var digits = String(number).split('');
 7190-      var key = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'];
 7191-      var roman = '';
 7192-      var i = 3;
 7193-      while (i--) {
 7194-        roman = (key[+digits.pop() + (i * 10)] || '') + roman;
 7195-      }
 7196-      return new Array(+digits.join('') + 1).join('M') + roman;
 7197-    };
 7198-
 7199-    Formula.SEARCH = function (find_text, within_text, position) {
 7200-      position = (typeof position === 'undefined') ? 0 : position;
 7201-      return within_text.toLowerCase().indexOf(find_text.toLowerCase(), position - 1) + 1;
 7202-    };
 7203-
 7204-    Formula.SPLIT = function (text, separator) {
 7205-      return _s.words(text, separator);
 7206-    };
 7207-
 7208-    Formula.SUBSTITUTE = function (text, old_text, new_text, occurrence) {
 7209-      if (!text || !old_text || !new_text) {
 7210-        return text;
 7211-      } else if (typeof occurrence === 'undefined') {
 7212-        return text.replace(new RegExp(old_text, 'g'), new_text);
 7213-      } else {
 7214-        var index = 0;
 7215-        var i = 0;
 7216-        while (text.indexOf(old_text, index) > 0) {
 7217-          index = text.indexOf(old_text, index + 1);
 7218-          i++;
 7219-          if (i === occurrence) {
 7220-            return text.substring(0, index) + new_text + text.substring(index + old_text.length);
 7221-          }
 7222-        }
 7223-      }
 7224-    };
 7225-
 7226-    Formula.T = function (value) {
 7227-      return (typeof value === "string") ? value : null;
 7228-    };
 7229-
 7230-    Formula.TEXT = function (value, format) {
 7231-      if (!value) {
 7232-        return '';
 7233-      }
 7234-
 7235-      if (value instanceof Object) {
 7236-        try {
 7237-          return JSON.stringify(value);
 7238-        } catch (err) {
 7239-          // ignore
 7240-          return '';
 7241-        }
 7242-      }
 7243-
 7244-      if (typeof value === 'string') {
 7245-        if (!format) { return value; }
 7246-        return (format.indexOf('0') >= 0) ? numeral(value).format(format) : moment(new Date(value)).format(format);
 7247-      }
 7248-
 7249-      if (value.toString && typeof value.toString === 'function') {
 7250-        return value.toString();
 7251-      }
 7252-
 7253-      return '';
 7254-    };
 7255-
 7256-    Formula.TRIM = function (text) {
 7257-      return _s.clean(text);
 7258-    };
 7259-
 7260-    Formula.UNICHAR = Formula.CHAR;
 7261-
 7262-    Formula.UNICODE = Formula.CODE;
 7263-
 7264-    Formula.UPPER = function (text) {
 7265-      return text.toUpperCase();
 7266-    };
 7267-
 7268-    Formula.VALUE = function (text) {
 7269-      return numeral().unformat(text);
 7270-    };
 7271-
 7272-    // Hashing function
 7273-    Formula.MD5 = function (data, key, raw) {
 7274-      return md5(data, key, raw);
 7275-    };
 7276-
 7277-    Formula.NUMERAL = function (number, format) {
 7278-      return numeral(number).format(format);
 7279-    };
 7280-
 7281-    // Excel Error Handling
 7282-    Formula.ISERR = function (value) {
 7283-      return (['#DIV/0!', '#NAME?', '#NUM!', '#NULL!', '#REF!', '#VALUE!'].indexOf(value) >= 0 ) ? true : false;
 7284-    };
 7285-
 7286-    Formula.ISERROR = function (value) {
 7287-      return Formula.ISERR(value) || value === '#N/A';
 7288-    };
 7289-
 7290-    Formula.IFERROR = function (value, valueIfError) {
 7291-      if (Formula.ISERROR(value)) {
 7292-        return valueIfError;
 7293-      }
 7294-
 7295-      return value;
 7296-    };
 7297-    return Formula;
 7298-  }
 7299-}).call(this);
 7300-
 7301diff --git a/lib/js-md5/md5.js b/lib/js-md5/md5.js
 7302deleted file mode 100644
 7303index 165f98b..0000000
 7304--- a/lib/js-md5/md5.js
 7305+++ /dev/null
 7306@@ -1,275 +0,0 @@
 7307-/*
 7308- * JavaScript MD5 1.0.1
 7309- * https://github.com/blueimp/JavaScript-MD5
 7310- *
 7311- * Copyright 2011, Sebastian Tschan
 7312- * https://blueimp.net
 7313- *
 7314- * Licensed under the MIT license:
 7315- * http://www.opensource.org/licenses/MIT
 7316- *
 7317- * Based on
 7318- * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 7319- * Digest Algorithm, as defined in RFC 1321.
 7320- * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
 7321- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 7322- * Distributed under the BSD License
 7323- * See http://pajhome.org.uk/crypt/md5 for more info.
 7324- */
 7325-
 7326-/*jslint bitwise: true */
 7327-/*global unescape, define */
 7328-
 7329-(function ($) {
 7330-  'use strict';
 7331-
 7332-  /*
 7333-   * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 7334-   * to work around bugs in some JS interpreters.
 7335-   */
 7336-  function safe_add(x, y) {
 7337-    var lsw = (x & 0xFFFF) + (y & 0xFFFF),
 7338-      msw = (x >> 16) + (y >> 16) + (lsw >> 16);
 7339-    return (msw << 16) | (lsw & 0xFFFF);
 7340-  }
 7341-
 7342-  /*
 7343-   * Bitwise rotate a 32-bit number to the left.
 7344-   */
 7345-  function bit_rol(num, cnt) {
 7346-    return (num << cnt) | (num >>> (32 - cnt));
 7347-  }
 7348-
 7349-  /*
 7350-   * These functions implement the four basic operations the algorithm uses.
 7351-   */
 7352-  function md5_cmn(q, a, b, x, s, t) {
 7353-    return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
 7354-  }
 7355-  function md5_ff(a, b, c, d, x, s, t) {
 7356-    return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
 7357-  }
 7358-  function md5_gg(a, b, c, d, x, s, t) {
 7359-    return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
 7360-  }
 7361-  function md5_hh(a, b, c, d, x, s, t) {
 7362-    return md5_cmn(b ^ c ^ d, a, b, x, s, t);
 7363-  }
 7364-  function md5_ii(a, b, c, d, x, s, t) {
 7365-    return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
 7366-  }
 7367-
 7368-  /*
 7369-   * Calculate the MD5 of an array of little-endian words, and a bit length.
 7370-   */
 7371-  function binl_md5(x, len) {
 7372-    /* append padding */
 7373-    x[len >> 5] |= 0x80 << (len % 32);
 7374-    x[(((len + 64) >>> 9) << 4) + 14] = len;
 7375-
 7376-    var i, olda, oldb, oldc, oldd,
 7377-      a =  1732584193,
 7378-      b = -271733879,
 7379-      c = -1732584194,
 7380-      d =  271733878;
 7381-
 7382-    for (i = 0; i < x.length; i += 16) {
 7383-      olda = a;
 7384-      oldb = b;
 7385-      oldc = c;
 7386-      oldd = d;
 7387-
 7388-      a = md5_ff(a, b, c, d, x[i],       7, -680876936);
 7389-      d = md5_ff(d, a, b, c, x[i +  1], 12, -389564586);
 7390-      c = md5_ff(c, d, a, b, x[i +  2], 17,  606105819);
 7391-      b = md5_ff(b, c, d, a, x[i +  3], 22, -1044525330);
 7392-      a = md5_ff(a, b, c, d, x[i +  4],  7, -176418897);
 7393-      d = md5_ff(d, a, b, c, x[i +  5], 12,  1200080426);
 7394-      c = md5_ff(c, d, a, b, x[i +  6], 17, -1473231341);
 7395-      b = md5_ff(b, c, d, a, x[i +  7], 22, -45705983);
 7396-      a = md5_ff(a, b, c, d, x[i +  8],  7,  1770035416);
 7397-      d = md5_ff(d, a, b, c, x[i +  9], 12, -1958414417);
 7398-      c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
 7399-      b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
 7400-      a = md5_ff(a, b, c, d, x[i + 12],  7,  1804603682);
 7401-      d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
 7402-      c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
 7403-      b = md5_ff(b, c, d, a, x[i + 15], 22,  1236535329);
 7404-
 7405-      a = md5_gg(a, b, c, d, x[i +  1],  5, -165796510);
 7406-      d = md5_gg(d, a, b, c, x[i +  6],  9, -1069501632);
 7407-      c = md5_gg(c, d, a, b, x[i + 11], 14,  643717713);
 7408-      b = md5_gg(b, c, d, a, x[i],      20, -373897302);
 7409-      a = md5_gg(a, b, c, d, x[i +  5],  5, -701558691);
 7410-      d = md5_gg(d, a, b, c, x[i + 10],  9,  38016083);
 7411-      c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
 7412-      b = md5_gg(b, c, d, a, x[i +  4], 20, -405537848);
 7413-      a = md5_gg(a, b, c, d, x[i +  9],  5,  568446438);
 7414-      d = md5_gg(d, a, b, c, x[i + 14],  9, -1019803690);
 7415-      c = md5_gg(c, d, a, b, x[i +  3], 14, -187363961);
 7416-      b = md5_gg(b, c, d, a, x[i +  8], 20,  1163531501);
 7417-      a = md5_gg(a, b, c, d, x[i + 13],  5, -1444681467);
 7418-      d = md5_gg(d, a, b, c, x[i +  2],  9, -51403784);
 7419-      c = md5_gg(c, d, a, b, x[i +  7], 14,  1735328473);
 7420-      b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
 7421-
 7422-      a = md5_hh(a, b, c, d, x[i +  5],  4, -378558);
 7423-      d = md5_hh(d, a, b, c, x[i +  8], 11, -2022574463);
 7424-      c = md5_hh(c, d, a, b, x[i + 11], 16,  1839030562);
 7425-      b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
 7426-      a = md5_hh(a, b, c, d, x[i +  1],  4, -1530992060);
 7427-      d = md5_hh(d, a, b, c, x[i +  4], 11,  1272893353);
 7428-      c = md5_hh(c, d, a, b, x[i +  7], 16, -155497632);
 7429-      b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
 7430-      a = md5_hh(a, b, c, d, x[i + 13],  4,  681279174);
 7431-      d = md5_hh(d, a, b, c, x[i],      11, -358537222);
 7432-      c = md5_hh(c, d, a, b, x[i +  3], 16, -722521979);
 7433-      b = md5_hh(b, c, d, a, x[i +  6], 23,  76029189);
 7434-      a = md5_hh(a, b, c, d, x[i +  9],  4, -640364487);
 7435-      d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
 7436-      c = md5_hh(c, d, a, b, x[i + 15], 16,  530742520);
 7437-      b = md5_hh(b, c, d, a, x[i +  2], 23, -995338651);
 7438-
 7439-      a = md5_ii(a, b, c, d, x[i],       6, -198630844);
 7440-      d = md5_ii(d, a, b, c, x[i +  7], 10,  1126891415);
 7441-      c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
 7442-      b = md5_ii(b, c, d, a, x[i +  5], 21, -57434055);
 7443-      a = md5_ii(a, b, c, d, x[i + 12],  6,  1700485571);
 7444-      d = md5_ii(d, a, b, c, x[i +  3], 10, -1894986606);
 7445-      c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
 7446-      b = md5_ii(b, c, d, a, x[i +  1], 21, -2054922799);
 7447-      a = md5_ii(a, b, c, d, x[i +  8],  6,  1873313359);
 7448-      d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
 7449-      c = md5_ii(c, d, a, b, x[i +  6], 15, -1560198380);
 7450-      b = md5_ii(b, c, d, a, x[i + 13], 21,  1309151649);
 7451-      a = md5_ii(a, b, c, d, x[i +  4],  6, -145523070);
 7452-      d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
 7453-      c = md5_ii(c, d, a, b, x[i +  2], 15,  718787259);
 7454-      b = md5_ii(b, c, d, a, x[i +  9], 21, -343485551);
 7455-
 7456-      a = safe_add(a, olda);
 7457-      b = safe_add(b, oldb);
 7458-      c = safe_add(c, oldc);
 7459-      d = safe_add(d, oldd);
 7460-    }
 7461-    return [a, b, c, d];
 7462-  }
 7463-
 7464-  /*
 7465-   * Convert an array of little-endian words to a string
 7466-   */
 7467-  function binl2rstr(input) {
 7468-    var i,
 7469-      output = '';
 7470-    for (i = 0; i < input.length * 32; i += 8) {
 7471-      output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
 7472-    }
 7473-    return output;
 7474-  }
 7475-
 7476-  /*
 7477-   * Convert a raw string to an array of little-endian words
 7478-   * Characters >255 have their high-byte silently ignored.
 7479-   */
 7480-  function rstr2binl(input) {
 7481-    var i,
 7482-      output = [];
 7483-    output[(input.length >> 2) - 1] = undefined;
 7484-    for (i = 0; i < output.length; i += 1) {
 7485-      output[i] = 0;
 7486-    }
 7487-    for (i = 0; i < input.length * 8; i += 8) {
 7488-      output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
 7489-    }
 7490-    return output;
 7491-  }
 7492-
 7493-  /*
 7494-   * Calculate the MD5 of a raw string
 7495-   */
 7496-  function rstr_md5(s) {
 7497-    return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
 7498-  }
 7499-
 7500-  /*
 7501-   * Calculate the HMAC-MD5, of a key and some data (raw strings)
 7502-   */
 7503-  function rstr_hmac_md5(key, data) {
 7504-    var i,
 7505-      bkey = rstr2binl(key),
 7506-      ipad = [],
 7507-      opad = [],
 7508-      hash;
 7509-    ipad[15] = opad[15] = undefined;
 7510-    if (bkey.length > 16) {
 7511-      bkey = binl_md5(bkey, key.length * 8);
 7512-    }
 7513-    for (i = 0; i < 16; i += 1) {
 7514-      ipad[i] = bkey[i] ^ 0x36363636;
 7515-      opad[i] = bkey[i] ^ 0x5C5C5C5C;
 7516-    }
 7517-    hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
 7518-    return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
 7519-  }
 7520-
 7521-  /*
 7522-   * Convert a raw string to a hex string
 7523-   */
 7524-  function rstr2hex(input) {
 7525-    var hex_tab = '0123456789abcdef',
 7526-      output = '',
 7527-      x,
 7528-      i;
 7529-    for (i = 0; i < input.length; i += 1) {
 7530-      x = input.charCodeAt(i);
 7531-      output += hex_tab.charAt((x >>> 4) & 0x0F) +
 7532-        hex_tab.charAt(x & 0x0F);
 7533-    }
 7534-    return output;
 7535-  }
 7536-
 7537-  /*
 7538-   * Encode a string as utf-8
 7539-   */
 7540-  function str2rstr_utf8(input) {
 7541-    return unescape(encodeURIComponent(input));
 7542-  }
 7543-
 7544-  /*
 7545-   * Take string arguments and return either raw or hex encoded strings
 7546-   */
 7547-  function raw_md5(s) {
 7548-    return rstr_md5(str2rstr_utf8(s));
 7549-  }
 7550-  function hex_md5(s) {
 7551-    return rstr2hex(raw_md5(s));
 7552-  }
 7553-  function raw_hmac_md5(k, d) {
 7554-    return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d));
 7555-  }
 7556-  function hex_hmac_md5(k, d) {
 7557-    return rstr2hex(raw_hmac_md5(k, d));
 7558-  }
 7559-
 7560-  function md5(string, key, raw) {
 7561-    if (!key) {
 7562-      if (!raw) {
 7563-        return hex_md5(string);
 7564-      }
 7565-      return raw_md5(string);
 7566-    }
 7567-    if (!raw) {
 7568-      return hex_hmac_md5(key, string);
 7569-    }
 7570-    return raw_hmac_md5(key, string);
 7571-  }
 7572-
 7573-  if (typeof define === 'function' && define.amd) {
 7574-    define(function () {
 7575-      return md5;
 7576-    });
 7577-  } else {
 7578-    $.md5 = md5;
 7579-  }
 7580-}(this));
 7581-
 7582diff --git a/lib/jstat/jstat.js b/lib/jstat/jstat.js
 7583deleted file mode 100644
 7584index 9f11b32..0000000
 7585--- a/lib/jstat/jstat.js
 7586+++ /dev/null
 7587@@ -1,3251 +0,0 @@
 7588-this.j$ = this.jStat = (function(Math, undefined) {
 7589-
 7590-// For quick reference.
 7591-  var concat = Array.prototype.concat;
 7592-  var slice = Array.prototype.slice;
 7593-  var toString = Object.prototype.toString;
 7594-
 7595-// Calculate correction for IEEE error
 7596-// TODO: This calculation can be improved.
 7597-  function calcRdx(n, m) {
 7598-    var val = n > m ? n : m;
 7599-    return Math.pow(10,
 7600-      17 - ~~(Math.log(((val > 0) ? val : -val)) * Math.LOG10E));
 7601-  }
 7602-
 7603-
 7604-  var isArray = Array.isArray || function isArray(arg) {
 7605-      return toString.call(arg) === '[object Array]';
 7606-    };
 7607-
 7608-
 7609-  function isFunction(arg) {
 7610-    return toString.call(arg) === '[object Function]';
 7611-  }
 7612-
 7613-
 7614-  function isNumber(arg) {
 7615-    return typeof arg === 'number' && arg === arg;
 7616-  }
 7617-
 7618-
 7619-// Converts the jStat matrix to vector.
 7620-  function toVector(arr) {
 7621-    return concat.apply([], arr);
 7622-  }
 7623-
 7624-
 7625-// The one and only jStat constructor.
 7626-  function jStat() {
 7627-    return new jStat._init(arguments);
 7628-  }
 7629-
 7630-
 7631-// TODO: Remove after all references in src files have been removed.
 7632-  jStat.fn = jStat.prototype;
 7633-
 7634-
 7635-// By separating the initializer from the constructor it's easier to handle
 7636-// always returning a new instance whether "new" was used or not.
 7637-  jStat._init = function _init(args) {
 7638-    var i;
 7639-
 7640-    // If first argument is an array, must be vector or matrix.
 7641-    if (isArray(args[0])) {
 7642-      // Check if matrix.
 7643-      if (isArray(args[0][0])) {
 7644-        // See if a mapping function was also passed.
 7645-        if (isFunction(args[1]))
 7646-          args[0] = jStat.map(args[0], args[1]);
 7647-        // Iterate over each is faster than this.push.apply(this, args[0].
 7648-        for (i = 0; i < args[0].length; i++)
 7649-          this[i] = args[0][i];
 7650-        this.length = args[0].length;
 7651-
 7652-        // Otherwise must be a vector.
 7653-      } else {
 7654-        this[0] = isFunction(args[1]) ? jStat.map(args[0], args[1]) : args[0];
 7655-        this.length = 1;
 7656-      }
 7657-
 7658-      // If first argument is number, assume creation of sequence.
 7659-    } else if (isNumber(args[0])) {
 7660-      this[0] = jStat.seq.apply(null, args);
 7661-      this.length = 1;
 7662-
 7663-      // Handle case when jStat object is passed to jStat.
 7664-    } else if (args[0] instanceof jStat) {
 7665-      // Duplicate the object and pass it back.
 7666-      return jStat(args[0].toArray());
 7667-
 7668-      // Unexpected argument value, return empty jStat object.
 7669-      // TODO: This is strange behavior. Shouldn't this throw or some such to let
 7670-      // the user know they had bad arguments?
 7671-    } else {
 7672-      this[0] = [];
 7673-      this.length = 1;
 7674-    }
 7675-
 7676-    return this;
 7677-  };
 7678-  jStat._init.prototype = jStat.prototype;
 7679-  jStat._init.constructor = jStat;
 7680-
 7681-
 7682-// Utility functions.
 7683-// TODO: for internal use only?
 7684-  jStat.utils = {
 7685-    calcRdx: calcRdx,
 7686-    isArray: isArray,
 7687-    isFunction: isFunction,
 7688-    isNumber: isNumber,
 7689-    toVector: toVector
 7690-  };
 7691-
 7692-
 7693-// Easily extend the jStat object.
 7694-// TODO: is this seriously necessary?
 7695-  jStat.extend = function extend(obj) {
 7696-    var i, j;
 7697-
 7698-    if (arguments.length === 1) {
 7699-      for (j in obj)
 7700-        jStat[j] = obj[j];
 7701-      return this;
 7702-    }
 7703-
 7704-    for (i = 1; i < arguments.length; i++) {
 7705-      for (j in arguments[i])
 7706-        obj[j] = arguments[i][j];
 7707-    }
 7708-
 7709-    return obj;
 7710-  };
 7711-
 7712-
 7713-// Returns the number of rows in the matrix.
 7714-  jStat.rows = function rows(arr) {
 7715-    return arr.length || 1;
 7716-  };
 7717-
 7718-
 7719-// Returns the number of columns in the matrix.
 7720-  jStat.cols = function cols(arr) {
 7721-    return arr[0].length || 1;
 7722-  };
 7723-
 7724-
 7725-// Returns the dimensions of the object { rows: i, cols: j }
 7726-  jStat.dimensions = function dimensions(arr) {
 7727-    return {
 7728-      rows: jStat.rows(arr),
 7729-      cols: jStat.cols(arr)
 7730-    };
 7731-  };
 7732-
 7733-
 7734-// Returns a specified row as a vector
 7735-  jStat.row = function row(arr, index) {
 7736-    return arr[index];
 7737-  };
 7738-
 7739-
 7740-// Returns the specified column as a vector
 7741-  jStat.col = function cols(arr, index) {
 7742-    var column = new Array(arr.length);
 7743-    for (var i = 0; i < arr.length; i++)
 7744-      column[i] = [arr[i][index]];
 7745-    return column;
 7746-  };
 7747-
 7748-
 7749-// Returns the diagonal of the matrix
 7750-  jStat.diag = function diag(arr) {
 7751-    var nrow = jStat.rows(arr);
 7752-    var res = new Array(nrow);
 7753-    for (var row = 0; row < nrow; row++)
 7754-      res[row] = [arr[row][row]];
 7755-    return res;
 7756-  };
 7757-
 7758-
 7759-// Returns the anti-diagonal of the matrix
 7760-  jStat.antidiag = function antidiag(arr) {
 7761-    var nrow = jStat.rows(arr) - 1;
 7762-    var res = new Array(nrow);
 7763-    for (var i = 0; nrow >= 0; nrow--, i++)
 7764-      res[i] = [arr[i][nrow]];
 7765-    return res;
 7766-  };
 7767-
 7768-// Transpose a matrix or array.
 7769-  jStat.transpose = function transpose(arr) {
 7770-    var obj = [];
 7771-    var objArr, rows, cols, j, i;
 7772-
 7773-    // Make sure arr is in matrix format.
 7774-    if (!isArray(arr[0]))
 7775-      arr = [arr];
 7776-
 7777-    rows = arr.length;
 7778-    cols = arr[0].length;
 7779-
 7780-    for (i = 0; i < cols; i++) {
 7781-      objArr = new Array(rows);
 7782-      for (j = 0; j < rows; j++)
 7783-        objArr[j] = arr[j][i];
 7784-      obj.push(objArr);
 7785-    }
 7786-
 7787-    // If obj is vector, return only single array.
 7788-    return obj.length === 1 ? obj[0] : obj;
 7789-  };
 7790-
 7791-
 7792-// Map a function to an array or array of arrays.
 7793-// "toAlter" is an internal variable.
 7794-  jStat.map = function map(arr, func, toAlter) {
 7795-    var row, nrow, ncol, res, col;
 7796-
 7797-    if (!isArray(arr[0]))
 7798-      arr = [arr];
 7799-
 7800-    nrow = arr.length;
 7801-    ncol = arr[0].length;
 7802-    res = toAlter ? arr : new Array(nrow);
 7803-
 7804-    for (row = 0; row < nrow; row++) {
 7805-      // if the row doesn't exist, create it
 7806-      if (!res[row])
 7807-        res[row] = new Array(ncol);
 7808-      for (col = 0; col < ncol; col++)
 7809-        res[row][col] = func(arr[row][col], row, col);
 7810-    }
 7811-
 7812-    return res.length === 1 ? res[0] : res;
 7813-  };
 7814-
 7815-
 7816-// Destructively alter an array.
 7817-  jStat.alter = function alter(arr, func) {
 7818-    return jStat.map(arr, func, true);
 7819-  };
 7820-
 7821-
 7822-// Generate a rows x cols matrix according to the supplied function.
 7823-  jStat.create = function  create(rows, cols, func) {
 7824-    var res = new Array(rows);
 7825-    var i, j;
 7826-
 7827-    if (isFunction(cols)) {
 7828-      func = cols;
 7829-      cols = rows;
 7830-    }
 7831-
 7832-    for (i = 0; i < rows; i++) {
 7833-      res[i] = new Array(cols);
 7834-      for (j = 0; j < cols; j++)
 7835-        res[i][j] = func(i, j);
 7836-    }
 7837-
 7838-    return res;
 7839-  };
 7840-
 7841-
 7842-  function retZero() { return 0; }
 7843-
 7844-
 7845-// Generate a rows x cols matrix of zeros.
 7846-  jStat.zeros = function zeros(rows, cols) {
 7847-    if (!isNumber(cols))
 7848-      cols = rows;
 7849-    return jStat.create(rows, cols, retZero);
 7850-  };
 7851-
 7852-
 7853-  function retOne() { return 1; }
 7854-
 7855-
 7856-// Generate a rows x cols matrix of ones.
 7857-  jStat.ones = function ones(rows, cols) {
 7858-    if (!isNumber(cols))
 7859-      cols = rows;
 7860-    return jStat.create(rows, cols, retOne);
 7861-  };
 7862-
 7863-
 7864-// Generate a rows x cols matrix of uniformly random numbers.
 7865-  jStat.rand = function rand(rows, cols) {
 7866-    if (!isNumber(cols))
 7867-      cols = rows;
 7868-    return jStat.create(rows, cols, Math.random);
 7869-  };
 7870-
 7871-
 7872-  function retIdent(i, j) { return i === j ? 1 : 0; }
 7873-
 7874-
 7875-// Generate an identity matrix of size row x cols.
 7876-  jStat.identity = function identity(rows, cols) {
 7877-    if (!isNumber(cols))
 7878-      cols = rows;
 7879-    return jStat.create(rows, cols, retIdent);
 7880-  };
 7881-
 7882-
 7883-// Tests whether a matrix is symmetric
 7884-  jStat.symmetric = function symmetric(arr) {
 7885-    var issymmetric = true;
 7886-    var size = arr.length;
 7887-    var row, col;
 7888-
 7889-    if (arr.length !== arr[0].length)
 7890-      return false;
 7891-
 7892-    for (row = 0; row < size; row++) {
 7893-      for (col = 0; col < size; col++)
 7894-        if (arr[col][row] !== arr[row][col])
 7895-          return false;
 7896-    }
 7897-
 7898-    return true;
 7899-  };
 7900-
 7901-
 7902-// Set all values to zero.
 7903-  jStat.clear = function clear(arr) {
 7904-    return jStat.alter(arr, retZero);
 7905-  };
 7906-
 7907-
 7908-// Generate sequence.
 7909-  jStat.seq = function seq(min, max, length, func) {
 7910-    if (!isFunction(func))
 7911-      func = false;
 7912-
 7913-    var arr = [];
 7914-    var hival = calcRdx(min, max);
 7915-    var step = (max * hival - min * hival) / ((length - 1) * hival);
 7916-    var current = min;
 7917-    var cnt;
 7918-
 7919-    // Current is assigned using a technique to compensate for IEEE error.
 7920-    // TODO: Needs better implementation.
 7921-    for (cnt = 0;
 7922-         current <= max;
 7923-         cnt++, current = (min * hival + step * hival * cnt) / hival) {
 7924-      arr.push((func ? func(current, cnt) : current));
 7925-    }
 7926-
 7927-    return arr;
 7928-  };
 7929-
 7930-
 7931-// TODO: Go over this entire implementation. Seems a tragic waste of resources
 7932-// doing all this work. Instead, and while ugly, use new Function() to generate
 7933-// a custom function for each static method.
 7934-
 7935-// Quick reference.
 7936-  var jProto = jStat.prototype;
 7937-
 7938-// Default length.
 7939-  jProto.length = 0;
 7940-
 7941-// For internal use only.
 7942-// TODO: Check if they're actually used, and if they are then rename them
 7943-// to _*
 7944-  jProto.push = Array.prototype.push;
 7945-  jProto.sort = Array.prototype.sort;
 7946-  jProto.splice = Array.prototype.splice;
 7947-  jProto.slice = Array.prototype.slice;
 7948-
 7949-
 7950-// Return a clean array.
 7951-  jProto.toArray = function toArray() {
 7952-    return this.length > 1 ? slice.call(this) : slice.call(this)[0];
 7953-  };
 7954-
 7955-
 7956-// Map a function to a matrix or vector.
 7957-  jProto.map = function map(func, toAlter) {
 7958-    return jStat(jStat.map(this, func, toAlter));
 7959-  };
 7960-
 7961-
 7962-// Destructively alter an array.
 7963-  jProto.alter = function alter(func) {
 7964-    jStat.alter(this, func);
 7965-    return this;
 7966-  };
 7967-
 7968-
 7969-// Extend prototype with methods that have no argument.
 7970-  (function(funcs) {
 7971-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
 7972-      jProto[passfunc] = function(func) {
 7973-        var self = this,
 7974-          results;
 7975-        // Check for callback.
 7976-        if (func) {
 7977-          setTimeout(function() {
 7978-            func.call(self, jProto[passfunc].call(self));
 7979-          });
 7980-          return this;
 7981-        }
 7982-        results = jStat[passfunc](this);
 7983-        return isArray(results) ? jStat(results) : results;
 7984-      };
 7985-    })(funcs[i]);
 7986-  })('transpose clear symmetric rows cols dimensions diag antidiag'.split(' '));
 7987-
 7988-
 7989-// Extend prototype with methods that have one argument.
 7990-  (function(funcs) {
 7991-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
 7992-      jProto[passfunc] = function(index, func) {
 7993-        var self = this;
 7994-        // check for callback
 7995-        if (func) {
 7996-          setTimeout(function() {
 7997-            func.call(self, jProto[passfunc].call(self, index));
 7998-          });
 7999-          return this;
 8000-        }
 8001-        return jStat(jStat[passfunc](this, index));
 8002-      };
 8003-    })(funcs[i]);
 8004-  })('row col'.split(' '));
 8005-
 8006-
 8007-// Extend prototype with simple shortcut methods.
 8008-  (function(funcs) {
 8009-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
 8010-      jProto[passfunc] = new Function(
 8011-        'return jStat(jStat.' + passfunc + '.apply(null, arguments));');
 8012-    })(funcs[i]);
 8013-  })('create zeros ones rand identity'.split(' '));
 8014-
 8015-
 8016-// Exposing jStat.
 8017-  return jStat;
 8018-
 8019-}(Math));
 8020-(function(jStat, Math) {
 8021-
 8022-  var isFunction = jStat.utils.isFunction;
 8023-
 8024-// Ascending functions for sort
 8025-  function ascNum(a, b) { return a - b; }
 8026-
 8027-  function clip(arg, min, max) {
 8028-    return Math.max(min, Math.min(arg, max));
 8029-  }
 8030-
 8031-
 8032-// sum of an array
 8033-  jStat.sum = function sum(arr) {
 8034-    var sum = 0;
 8035-    var i = arr.length;
 8036-    var tmp;
 8037-    while (--i >= 0)
 8038-      sum += arr[i];
 8039-    return sum;
 8040-  };
 8041-
 8042-
 8043-// sum squared
 8044-  jStat.sumsqrd = function sumsqrd(arr) {
 8045-    var sum = 0;
 8046-    var i = arr.length;
 8047-    while (--i >= 0)
 8048-      sum += arr[i] * arr[i];
 8049-    return sum;
 8050-  };
 8051-
 8052-
 8053-// sum of squared errors of prediction (SSE)
 8054-  jStat.sumsqerr = function sumsqerr(arr) {
 8055-    var mean = jStat.mean(arr);
 8056-    var sum = 0;
 8057-    var i = arr.length;
 8058-    var tmp;
 8059-    while (--i >= 0) {
 8060-      tmp = arr[i] - mean;
 8061-      sum += tmp * tmp;
 8062-    }
 8063-    return sum;
 8064-  };
 8065-
 8066-
 8067-// product of an array
 8068-  jStat.product = function product(arr) {
 8069-    var prod = 1;
 8070-    var i = arr.length;
 8071-    while (--i >= 0)
 8072-      prod *= arr[i];
 8073-    return prod;
 8074-  };
 8075-
 8076-
 8077-// minimum value of an array
 8078-  jStat.min = function min(arr) {
 8079-    var low = arr[0];
 8080-    var i = 0;
 8081-    while (++i < arr.length)
 8082-      if (arr[i] < low)
 8083-        low = arr[i];
 8084-    return low;
 8085-  };
 8086-
 8087-
 8088-// maximum value of an array
 8089-  jStat.max = function max(arr) {
 8090-    var high = arr[0];
 8091-    var i = 0;
 8092-    while (++i < arr.length)
 8093-      if (arr[i] > high)
 8094-        high = arr[i];
 8095-    return high;
 8096-  };
 8097-
 8098-
 8099-// mean value of an array
 8100-  jStat.mean = function mean(arr) {
 8101-    return jStat.sum(arr) / arr.length;
 8102-  };
 8103-
 8104-
 8105-// mean squared error (MSE)
 8106-  jStat.meansqerr = function meansqerr(arr) {
 8107-    return jStat.sumsqerr(arr) / arr.length;
 8108-  };
 8109-
 8110-
 8111-// geometric mean of an array
 8112-  jStat.geomean = function geomean(arr) {
 8113-    return Math.pow(jStat.product(arr), 1 / arr.length);
 8114-  };
 8115-
 8116-
 8117-// median of an array
 8118-  jStat.median = function median(arr) {
 8119-    var arrlen = arr.length;
 8120-    var _arr = arr.slice().sort(ascNum);
 8121-    // check if array is even or odd, then return the appropriate
 8122-    return !(arrlen & 1)
 8123-      ? (_arr[(arrlen / 2) - 1 ] + _arr[(arrlen / 2)]) / 2
 8124-      : _arr[(arrlen / 2) | 0 ];
 8125-  };
 8126-
 8127-
 8128-// cumulative sum of an array
 8129-  jStat.cumsum = function cumsum(arr) {
 8130-    var len = arr.length;
 8131-    var sums = new Array(len);
 8132-    var i;
 8133-    sums[0] = arr[0];
 8134-    for (i = 1; i < len; i++)
 8135-      sums[i] = sums[i - 1] + arr[i];
 8136-    return sums;
 8137-  };
 8138-
 8139-
 8140-// successive differences of a sequence
 8141-  jStat.diff = function diff(arr) {
 8142-    var diffs = [];
 8143-    var arrLen = arr.length;
 8144-    var i;
 8145-    for (i = 1; i < arrLen; i++)
 8146-      diffs.push(arr[i] - arr[i - 1]);
 8147-    return diffs;
 8148-  };
 8149-
 8150-
 8151-// mode of an array
 8152-// if there are multiple modes of an array, return all of them
 8153-// is this the appropriate way of handling it?
 8154-  jStat.mode = function mode(arr) {
 8155-    var arrLen = arr.length;
 8156-    var _arr = arr.slice().sort(ascNum);
 8157-    var count = 1;
 8158-    var maxCount = 0;
 8159-    var numMaxCount = 0;
 8160-    var mode_arr = [];
 8161-    var i;
 8162-
 8163-    for (i = 0; i < arrLen; i++) {
 8164-      if (_arr[i] === _arr[i + 1]) {
 8165-        count++;
 8166-      } else {
 8167-        if (count > maxCount) {
 8168-          mode_arr = [_arr[i]];
 8169-          maxCount = count;
 8170-          numMaxCount = 0;
 8171-        }
 8172-        // are there multiple max counts
 8173-        else if (count === maxCount) {
 8174-          mode_arr.push(_arr[i]);
 8175-          numMaxCount++;
 8176-        }
 8177-        // resetting count for new value in array
 8178-        count = 1;
 8179-      }
 8180-    }
 8181-
 8182-    return numMaxCount === 0 ? mode_arr[0] : mode_arr;
 8183-  };
 8184-
 8185-
 8186-// range of an array
 8187-  jStat.range = function range(arr) {
 8188-    return jStat.max(arr) - jStat.min(arr);
 8189-  };
 8190-
 8191-// variance of an array
 8192-// flag indicates population vs sample
 8193-  jStat.variance = function variance(arr, flag) {
 8194-    return jStat.sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
 8195-  };
 8196-
 8197-
 8198-// standard deviation of an array
 8199-// flag indicates population vs sample
 8200-  jStat.stdev = function stdev(arr, flag) {
 8201-    return Math.sqrt(jStat.variance(arr, flag));
 8202-  };
 8203-
 8204-
 8205-// mean deviation (mean absolute deviation) of an array
 8206-  jStat.meandev = function meandev(arr) {
 8207-    var devSum = 0;
 8208-    var mean = jStat.mean(arr);
 8209-    var i;
 8210-    for (i = arr.length - 1; i >= 0; i--)
 8211-      devSum += Math.abs(arr[i] - mean);
 8212-    return devSum / arr.length;
 8213-  };
 8214-
 8215-
 8216-// median deviation (median absolute deviation) of an array
 8217-  jStat.meddev = function meddev(arr) {
 8218-    var devSum = 0;
 8219-    var median = jStat.median(arr);
 8220-    var i;
 8221-    for (i = arr.length - 1; i >= 0; i--)
 8222-      devSum += Math.abs(arr[i] - median);
 8223-    return devSum / arr.length;
 8224-  };
 8225-
 8226-
 8227-// coefficient of variation
 8228-  jStat.coeffvar = function coeffvar(arr) {
 8229-    return jStat.stdev(arr) / jStat.mean(arr);
 8230-  };
 8231-
 8232-
 8233-// quartiles of an array
 8234-  jStat.quartiles = function quartiles(arr) {
 8235-    var arrlen = arr.length;
 8236-    var _arr = arr.slice().sort(ascNum);
 8237-    return [
 8238-      _arr[ Math.round((arrlen) / 4) - 1 ],
 8239-      _arr[ Math.round((arrlen) / 2) - 1 ],
 8240-      _arr[ Math.round((arrlen) * 3 / 4) - 1 ]
 8241-    ];
 8242-  };
 8243-
 8244-
 8245-// Arbitary quantiles of an array. Direct port of the scipy.stats
 8246-// implementation by Pierre GF Gerard-Marchant.
 8247-  jStat.quantiles = function quantiles(arr, quantilesArray, alphap, betap) {
 8248-    var sortedArray = arr.slice().sort(ascNum);
 8249-    var quantileVals = [quantilesArray.length];
 8250-    var n = arr.length;
 8251-    var i, p, m, aleph, k, gamma;
 8252-
 8253-    if (typeof alphap === 'undefined')
 8254-      alphap = 3 / 8;
 8255-    if (typeof betap === 'undefined')
 8256-      betap = 3 / 8;
 8257-
 8258-    for (i = 0; i < quantilesArray.length; i++) {
 8259-      p = quantilesArray[i];
 8260-      m = alphap + p * (1 - alphap - betap);
 8261-      aleph = n * p + m;
 8262-      k = Math.floor(clip(aleph, 1, n - 1));
 8263-      gamma = clip(aleph - k, 0, 1);
 8264-      quantileVals[i] = (1 - gamma) * sortedArray[k - 1] + gamma * sortedArray[k];
 8265-    }
 8266-
 8267-    return quantileVals;
 8268-  };
 8269-
 8270-// The percentile rank of score in a given array. Returns the percentage
 8271-// of all values in the input array that are less than (kind='strict') or
 8272-// less or equal than (kind='weak') score. Default is weak.
 8273-  jStat.percentileOfScore = function percentileOfScore(arr, score, kind) {
 8274-    var counter = 0;
 8275-    var len = arr.length;
 8276-    var strict = false;
 8277-    var value, i;
 8278-
 8279-    if (kind === 'strict')
 8280-      strict = true;
 8281-
 8282-    for (i = 0; i < len; i++) {
 8283-      value = arr[i];
 8284-      if ((strict && value < score) ||
 8285-        (!strict && value <= score)) {
 8286-        counter++;
 8287-      }
 8288-    }
 8289-
 8290-    return counter / len;
 8291-  };
 8292-
 8293-// covariance of two arrays
 8294-  jStat.covariance = function covariance(arr1, arr2) {
 8295-    var u = jStat.mean(arr1);
 8296-    var v = jStat.mean(arr2);
 8297-    var arr1Len = arr1.length;
 8298-    var sq_dev = new Array(arr1Len);
 8299-    var i;
 8300-
 8301-    for (i = 0; i < arr1Len; i++)
 8302-      sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
 8303-
 8304-    return jStat.sum(sq_dev) / (arr1Len - 1);
 8305-  };
 8306-
 8307-
 8308-// (pearson's) population correlation coefficient, rho
 8309-  jStat.corrcoeff = function corrcoeff(arr1, arr2) {
 8310-    return jStat.covariance(arr1, arr2) /
 8311-      jStat.stdev(arr1, 1) /
 8312-      jStat.stdev(arr2, 1);
 8313-  };
 8314-
 8315-
 8316-  var jProto = jStat.prototype;
 8317-
 8318-
 8319-// Extend jProto with method for calculating cumulative sums, as it does not
 8320-// run again in case of true.
 8321-// If a matrix is passed, automatically assume operation should be done on the
 8322-// columns.
 8323-  jProto.cumsum = function(fullbool, func) {
 8324-    var arr = [];
 8325-    var i = 0;
 8326-    var tmpthis = this;
 8327-
 8328-    // Assignment reassignation depending on how parameters were passed in.
 8329-    if (isFunction(fullbool)) {
 8330-      func = fullbool;
 8331-      fullbool = false;
 8332-    }
 8333-
 8334-    // Check if a callback was passed with the function.
 8335-    if (func) {
 8336-      setTimeout(function() {
 8337-        func.call(tmpthis, jProto.cumsum.call(tmpthis, fullbool));
 8338-      });
 8339-      return this;
 8340-    }
 8341-
 8342-    // Check if matrix and run calculations.
 8343-    if (this.length > 1) {
 8344-      tmpthis = fullbool === true ? this : this.transpose();
 8345-      for (; i < tmpthis.length; i++)
 8346-        arr[i] = jStat.cumsum(tmpthis[i]);
 8347-      return arr;
 8348-    }
 8349-
 8350-    return jStat.cumsum(this[0], fullbool);
 8351-  };
 8352-
 8353-
 8354-// Extend jProto with methods which don't require arguments and work on columns.
 8355-  (function(funcs) {
 8356-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
 8357-      // If a matrix is passed, automatically assume operation should be done on
 8358-      // the columns.
 8359-      jProto[passfunc] = function(fullbool, func) {
 8360-        var arr = [];
 8361-        var i = 0;
 8362-        var tmpthis = this;
 8363-        // Assignment reassignation depending on how parameters were passed in.
 8364-        if (isFunction(fullbool)) {
 8365-          func = fullbool;
 8366-          fullbool = false;
 8367-        }
 8368-        // Check if a callback was passed with the function.
 8369-        if (func) {
 8370-          setTimeout(function() {
 8371-            func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool));
 8372-          });
 8373-          return this;
 8374-        }
 8375-        // Check if matrix and run calculations.
 8376-        if (this.length > 1) {
 8377-          tmpthis = fullbool === true ? this : this.transpose();
 8378-          for (; i < tmpthis.length; i++)
 8379-            arr[i] = jStat[passfunc](tmpthis[i]);
 8380-          return fullbool === true
 8381-            ? jStat[passfunc](jStat.utils.toVector(arr))
 8382-            : arr;
 8383-        }
 8384-        // Pass fullbool if only vector, not a matrix. for variance and stdev.
 8385-        return jStat[passfunc](this[0], fullbool);
 8386-      };
 8387-    })(funcs[i]);
 8388-  })(('sum sumsqrd sumsqerr product min max mean meansqerr geomean median diff ' +
 8389-  'mode range variance stdev meandev meddev coeffvar quartiles').split(' '));
 8390-
 8391-
 8392-// Extend jProto with functions that take arguments. Operations on matrices are
 8393-// done on columns.
 8394-  (function(funcs) {
 8395-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
 8396-      jProto[passfunc] = function() {
 8397-        var arr = [];
 8398-        var i = 0;
 8399-        var tmpthis = this;
 8400-        var args = Array.prototype.slice.call(arguments);
 8401-
 8402-        // If the last argument is a function, we assume it's a callback; we
 8403-        // strip the callback out and call the function again.
 8404-        if (isFunction(args[args.length - 1])) {
 8405-          var callbackFunction = args[args.length - 1];
 8406-          var argsToPass = args.slice(0, args.length - 1);
 8407-
 8408-          setTimeout(function() {
 8409-            callbackFunction.call(tmpthis,
 8410-              jProto[passfunc].apply(tmpthis, argsToPass));
 8411-          });
 8412-          return this;
 8413-
 8414-          // Otherwise we curry the function args and call normally.
 8415-        } else {
 8416-          var callbackFunction = undefined;
 8417-          var curriedFunction = function curriedFunction(vector) {
 8418-            return jStat[passfunc].apply(tmpthis, [vector].concat(args));
 8419-          }
 8420-        }
 8421-
 8422-        // If this is a matrix, run column-by-column.
 8423-        if (this.length > 1) {
 8424-          tmpthis = tmpthis.transpose();
 8425-          for (; i < tmpthis.length; i++)
 8426-            arr[i] = curriedFunction(tmpthis[i]);
 8427-          return arr;
 8428-        }
 8429-
 8430-        // Otherwise run on the vector.
 8431-        return curriedFunction(this[0]);
 8432-      };
 8433-    })(funcs[i]);
 8434-  })('quantiles percentileOfScore'.split(' '));
 8435-
 8436-}(this.jStat, Math));
 8437-// Special functions //
 8438-(function(jStat, Math) {
 8439-
 8440-// Log-gamma function
 8441-  jStat.gammaln = function gammaln(x) {
 8442-    var j = 0;
 8443-    var cof = [
 8444-      76.18009172947146, -86.50532032941677, 24.01409824083091,
 8445-      -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5
 8446-    ];
 8447-    var ser = 1.000000000190015;
 8448-    var xx, y, tmp;
 8449-    tmp = (y = xx = x) + 5.5;
 8450-    tmp -= (xx + 0.5) * Math.log(tmp);
 8451-    for (; j < 6; j++)
 8452-      ser += cof[j] / ++y;
 8453-    return Math.log(2.5066282746310005 * ser / xx) - tmp;
 8454-  };
 8455-
 8456-
 8457-// gamma of x
 8458-  jStat.gammafn = function gammafn(x) {
 8459-    var p = [-1.716185138865495, 24.76565080557592, -379.80425647094563,
 8460-      629.3311553128184, 866.9662027904133, -31451.272968848367,
 8461-      -36144.413418691176, 66456.14382024054
 8462-    ];
 8463-    var q = [-30.8402300119739, 315.35062697960416, -1015.1563674902192,
 8464-      -3107.771671572311, 22538.118420980151, 4755.8462775278811,
 8465-      -134659.9598649693, -115132.2596755535];
 8466-    var fact = false;
 8467-    var n = 0;
 8468-    var xden = 0;
 8469-    var xnum = 0;
 8470-    var y = x;
 8471-    var i, z, yi, res, sum, ysq;
 8472-    if (y <= 0) {
 8473-      res = y % 1 + 3.6e-16;
 8474-      if (res) {
 8475-        fact = (!(y & 1) ? 1 : -1) * Math.PI / Math.sin(Math.PI * res);
 8476-        y = 1 - y;
 8477-      } else {
 8478-        return Infinity;
 8479-      }
 8480-    }
 8481-    yi = y;
 8482-    if (y < 1) {
 8483-      z = y++;
 8484-    } else {
 8485-      z = (y -= n = (y | 0) - 1) - 1;
 8486-    }
 8487-    for (i = 0; i < 8; ++i) {
 8488-      xnum = (xnum + p[i]) * z;
 8489-      xden = xden * z + q[i];
 8490-    }
 8491-    res = xnum / xden + 1;
 8492-    if (yi < y) {
 8493-      res /= yi;
 8494-    } else if (yi > y) {
 8495-      for (i = 0; i < n; ++i) {
 8496-        res *= y;
 8497-        y++;
 8498-      }
 8499-    }
 8500-    if (fact) {
 8501-      res = fact / res;
 8502-    }
 8503-    return res;
 8504-  };
 8505-
 8506-
 8507-// lower incomplete gamma function P(a,x)
 8508-  jStat.gammap = function gammap(a, x) {
 8509-    var aln = jStat.gammaln(a);
 8510-    var ap = a;
 8511-    var sum = 1 / a;
 8512-    var del = sum;
 8513-    var b = x + 1 - a;
 8514-    var c = 1 / 1.0e-30;
 8515-    var d = 1 / b;
 8516-    var h = d;
 8517-    var i = 1;
 8518-    // calculate maximum number of itterations required for a
 8519-    var ITMAX = -~(Math.log((a >= 1) ? a : 1 / a) * 8.5 + a * 0.4 + 17);
 8520-    var an, endval;
 8521-
 8522-    if (x < 0 || a <= 0) {
 8523-      return NaN;
 8524-    } else if (x < a + 1) {
 8525-      for (; i <= ITMAX; i++) {
 8526-        sum += del *= x / ++ap;
 8527-      }
 8528-      return sum * Math.exp(-x + a * Math.log(x) - (aln));
 8529-    }
 8530-
 8531-    for (; i <= ITMAX; i++) {
 8532-      an = -i * (i - a);
 8533-      b += 2;
 8534-      d = an * d + b;
 8535-      c = b + an / c;
 8536-      d = 1 / d;
 8537-      h *= d * c;
 8538-    }
 8539-
 8540-    return 1 - h * Math.exp(-x + a * Math.log(x) - (aln));
 8541-  };
 8542-
 8543-
 8544-// natural log factorial of n
 8545-  jStat.factorialln = function factorialln(n) {
 8546-    return n < 0 ? NaN : jStat.gammaln(n + 1);
 8547-  };
 8548-
 8549-// factorial of n
 8550-  jStat.factorial = function factorial(n) {
 8551-    return n < 0 ? NaN : jStat.gammafn(n + 1);
 8552-  };
 8553-
 8554-// combinations of n, m
 8555-  jStat.combination = function combination(n, m) {
 8556-    // make sure n or m don't exceed the upper limit of usable values
 8557-    return (n > 170 || m > 170)
 8558-      ? Math.exp(jStat.combinationln(n, m))
 8559-      : (jStat.factorial(n) / jStat.factorial(m)) / jStat.factorial(n - m);
 8560-  };
 8561-
 8562-
 8563-  jStat.combinationln = function combinationln(n, m){
 8564-    return jStat.factorialln(n) - jStat.factorialln(m) - jStat.factorialln(n - m);
 8565-  };
 8566-
 8567-
 8568-// permutations of n, m
 8569-  jStat.permutation = function permutation(n, m) {
 8570-    return jStat.factorial(n) / jStat.factorial(n - m);
 8571-  };
 8572-
 8573-
 8574-// beta function
 8575-  jStat.betafn = function betafn(x, y) {
 8576-    // ensure arguments are positive
 8577-    if (x <= 0 || y <= 0)
 8578-      return undefined;
 8579-    // make sure x + y doesn't exceed the upper limit of usable values
 8580-    return (x + y > 170)
 8581-      ? Math.exp(jStat.betaln(x, y))
 8582-      : jStat.gammafn(x) * jStat.gammafn(y) / jStat.gammafn(x + y);
 8583-  };
 8584-
 8585-
 8586-// natural logarithm of beta function
 8587-  jStat.betaln = function betaln(x, y) {
 8588-    return jStat.gammaln(x) + jStat.gammaln(y) - jStat.gammaln(x + y);
 8589-  };
 8590-
 8591-
 8592-// Evaluates the continued fraction for incomplete beta function by modified
 8593-// Lentz's method.
 8594-  jStat.betacf = function betacf(x, a, b) {
 8595-    var fpmin = 1e-30;
 8596-    var m = 1;
 8597-    var qab = a + b;
 8598-    var qap = a + 1;
 8599-    var qam = a - 1;
 8600-    var c = 1;
 8601-    var d = 1 - qab * x / qap;
 8602-    var m2, aa, del, h;
 8603-
 8604-    // These q's will be used in factors that occur in the coefficients
 8605-    if (Math.abs(d) < fpmin)
 8606-      d = fpmin;
 8607-    d = 1 / d;
 8608-    h = d;
 8609-
 8610-    for (; m <= 100; m++) {
 8611-      m2 = 2 * m;
 8612-      aa = m * (b - m) * x / ((qam + m2) * (a + m2));
 8613-      // One step (the even one) of the recurrence
 8614-      d = 1 + aa * d;
 8615-      if (Math.abs(d) < fpmin)
 8616-        d = fpmin;
 8617-      c = 1 + aa / c;
 8618-      if (Math.abs(c) < fpmin)
 8619-        c = fpmin;
 8620-      d = 1 / d;
 8621-      h *= d * c;
 8622-      aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
 8623-      // Next step of the recurrence (the odd one)
 8624-      d = 1 + aa * d;
 8625-      if (Math.abs(d) < fpmin)
 8626-        d = fpmin;
 8627-      c = 1 + aa / c;
 8628-      if (Math.abs(c) < fpmin)
 8629-        c = fpmin;
 8630-      d = 1 / d;
 8631-      del = d * c;
 8632-      h *= del;
 8633-      if (Math.abs(del - 1.0) < 3e-7)
 8634-        break;
 8635-    }
 8636-
 8637-    return h;
 8638-  };
 8639-
 8640-
 8641-// Returns the inverse incomplte gamma function
 8642-  jStat.gammapinv = function gammapinv(p, a) {
 8643-    var j = 0;
 8644-    var a1 = a - 1;
 8645-    var EPS = 1e-8;
 8646-    var gln = jStat.gammaln(a);
 8647-    var x, err, t, u, pp, lna1, afac;
 8648-
 8649-    if (p >= 1)
 8650-      return Math.max(100, a + 100 * Math.sqrt(a));
 8651-    if (p <= 0)
 8652-      return 0;
 8653-    if (a > 1) {
 8654-      lna1 = Math.log(a1);
 8655-      afac = Math.exp(a1 * (lna1 - 1) - gln);
 8656-      pp = (p < 0.5) ? p : 1 - p;
 8657-      t = Math.sqrt(-2 * Math.log(pp));
 8658-      x = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;
 8659-      if (p < 0.5)
 8660-        x = -x;
 8661-      x = Math.max(1e-3,
 8662-        a * Math.pow(1 - 1 / (9 * a) - x / (3 * Math.sqrt(a)), 3));
 8663-    } else {
 8664-      t = 1 - a * (0.253 + a * 0.12);
 8665-      if (p < t)
 8666-        x = Math.pow(p / t, 1 / a);
 8667-      else
 8668-        x = 1 - Math.log(1 - (p - t) / (1 - t));
 8669-    }
 8670-
 8671-    for(; j < 12; j++) {
 8672-      if (x <= 0)
 8673-        return 0;
 8674-      err = jStat.gammap(a, x) - p;
 8675-      if (a > 1)
 8676-        t = afac * Math.exp(-(x - a1) + a1 * (Math.log(x) - lna1));
 8677-      else
 8678-        t = Math.exp(-x + a1 * Math.log(x) - gln);
 8679-      u = err / t;
 8680-      x -= (t = u / (1 - 0.5 * Math.min(1, u * ((a - 1) / x - 1))));
 8681-      if (x <= 0)
 8682-        x = 0.5 * (x + t);
 8683-      if (Math.abs(t) < EPS * x)
 8684-        break;
 8685-    }
 8686-
 8687-    return x;
 8688-  };
 8689-
 8690-
 8691-// Returns the error function erf(x)
 8692-  jStat.erf = function erf(x) {
 8693-    var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
 8694-      -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
 8695-      4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
 8696-      1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
 8697-      6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
 8698-      -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
 8699-      -6.886027e-12, 8.94487e-13, 3.13092e-13,
 8700-      -1.12708e-13, 3.81e-16, 7.106e-15,
 8701-      -1.523e-15, -9.4e-17, 1.21e-16,
 8702-      -2.8e-17];
 8703-    var j = cof.length - 1;
 8704-    var isneg = false;
 8705-    var d = 0;
 8706-    var dd = 0;
 8707-    var t, ty, tmp, res;
 8708-
 8709-    if (x < 0) {
 8710-      x = -x;
 8711-      isneg = true;
 8712-    }
 8713-
 8714-    t = 2 / (2 + x);
 8715-    ty = 4 * t - 2;
 8716-
 8717-    for(; j > 0; j--) {
 8718-      tmp = d;
 8719-      d = ty * d - dd + cof[j];
 8720-      dd = tmp;
 8721-    }
 8722-
 8723-    res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
 8724-    return isneg ? res - 1 : 1 - res;
 8725-  };
 8726-
 8727-
 8728-// Returns the complmentary error function erfc(x)
 8729-  jStat.erfc = function erfc(x) {
 8730-    return 1 - jStat.erf(x);
 8731-  };
 8732-
 8733-
 8734-// Returns the inverse of the complementary error function
 8735-  jStat.erfcinv = function erfcinv(p) {
 8736-    var j = 0;
 8737-    var x, err, t, pp;
 8738-    if (p >= 2)
 8739-      return -100;
 8740-    if (p <= 0)
 8741-      return 100;
 8742-    pp = (p < 1) ? p : 2 - p;
 8743-    t = Math.sqrt(-2 * Math.log(pp / 2));
 8744-    x = -0.70711 * ((2.30753 + t * 0.27061) /
 8745-      (1 + t * (0.99229 + t * 0.04481)) - t);
 8746-    for (; j < 2; j++) {
 8747-      err = jStat.erfc(x) - pp;
 8748-      x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);
 8749-    }
 8750-    return (p < 1) ? x : -x;
 8751-  };
 8752-
 8753-
 8754-// Returns the inverse of the incomplete beta function
 8755-  jStat.ibetainv = function ibetainv(p, a, b) {
 8756-    var EPS = 1e-8;
 8757-    var a1 = a - 1;
 8758-    var b1 = b - 1;
 8759-    var j = 0;
 8760-    var lna, lnb, pp, t, u, err, x, al, h, w, afac;
 8761-    if (p <= 0)
 8762-      return 0;
 8763-    if (p >= 1)
 8764-      return 1;
 8765-    if (a >= 1 && b >= 1) {
 8766-      pp = (p < 0.5) ? p : 1 - p;
 8767-      t = Math.sqrt(-2 * Math.log(pp));
 8768-      x = (2.30753 + t * 0.27061) / (1 + t* (0.99229 + t * 0.04481)) - t;
 8769-      if (p < 0.5)
 8770-        x = -x;
 8771-      al = (x * x - 3) / 6;
 8772-      h = 2 / (1 / (2 * a - 1)  + 1 / (2 * b - 1));
 8773-      w = (x * Math.sqrt(al + h) / h) - (1 / (2 * b - 1) - 1 / (2 * a - 1)) *
 8774-        (al + 5 / 6 - 2 / (3 * h));
 8775-      x = a / (a + b * Math.exp(2 * w));
 8776-    } else {
 8777-      lna = Math.log(a / (a + b));
 8778-      lnb = Math.log(b / (a + b));
 8779-      t = Math.exp(a * lna) / a;
 8780-      u = Math.exp(b * lnb) / b;
 8781-      w = t + u;
 8782-      if (p < t / w)
 8783-        x = Math.pow(a * w * p, 1 / a);
 8784-      else
 8785-        x = 1 - Math.pow(b * w * (1 - p), 1 / b);
 8786-    }
 8787-    afac = -jStat.gammaln(a) - jStat.gammaln(b) + jStat.gammaln(a + b);
 8788-    for(; j < 10; j++) {
 8789-      if (x === 0 || x === 1)
 8790-        return x;
 8791-      err = jStat.ibeta(x, a, b) - p;
 8792-      t = Math.exp(a1 * Math.log(x) + b1 * Math.log(1 - x) + afac);
 8793-      u = err / t;
 8794-      x -= (t = u / (1 - 0.5 * Math.min(1, u * (a1 / x - b1 / (1 - x)))));
 8795-      if (x <= 0)
 8796-        x = 0.5 * (x + t);
 8797-      if (x >= 1)
 8798-        x = 0.5 * (x + t + 1);
 8799-      if (Math.abs(t) < EPS * x && j > 0)
 8800-        break;
 8801-    }
 8802-    return x;
 8803-  };
 8804-
 8805-
 8806-// Returns the incomplete beta function I_x(a,b)
 8807-  jStat.ibeta = function ibeta(x, a, b) {
 8808-    // Factors in front of the continued fraction.
 8809-    var bt = (x === 0 || x === 1) ?  0 :
 8810-      Math.exp(jStat.gammaln(a + b) - jStat.gammaln(a) -
 8811-        jStat.gammaln(b) + a * Math.log(x) + b *
 8812-        Math.log(1 - x));
 8813-    if (x < 0 || x > 1)
 8814-      return false;
 8815-    if (x < (a + 1) / (a + b + 2))
 8816-    // Use continued fraction directly.
 8817-      return bt * jStat.betacf(x, a, b) / a;
 8818-    // else use continued fraction after making the symmetry transformation.
 8819-    return 1 - bt * jStat.betacf(1 - x, b, a) / b;
 8820-  };
 8821-
 8822-
 8823-// Returns a normal deviate (mu=0, sigma=1).
 8824-// If n and m are specified it returns a object of normal deviates.
 8825-  jStat.randn = function randn(n, m) {
 8826-    var u, v, x, y, q, mat;
 8827-    if (!m)
 8828-      m = n;
 8829-    if (n)
 8830-      return jStat.create(n, m, function() { return jStat.randn(); });
 8831-    do {
 8832-      u = Math.random();
 8833-      v = 1.7156 * (Math.random() - 0.5);
 8834-      x = u - 0.449871;
 8835-      y = Math.abs(v) + 0.386595;
 8836-      q = x * x + y * (0.19600 * y - 0.25472 * x);
 8837-    } while (q > 0.27597 && (q > 0.27846 || v * v > -4 * Math.log(u) * u * u));
 8838-    return v / u;
 8839-  };
 8840-
 8841-
 8842-// Returns a gamma deviate by the method of Marsaglia and Tsang.
 8843-  jStat.randg = function randg(shape, n, m) {
 8844-    var oalph = shape;
 8845-    var a1, a2, u, v, x, mat;
 8846-    if (!m)
 8847-      m = n;
 8848-    if (!shape)
 8849-      shape = 1;
 8850-    if (n) {
 8851-      mat = jStat.zeros(n,m);
 8852-      mat.alter(function() { return jStat.randg(shape); });
 8853-      return mat;
 8854-    }
 8855-    if (shape < 1)
 8856-      shape += 1;
 8857-    a1 = shape - 1 / 3;
 8858-    a2 = 1 / Math.sqrt(9 * a1);
 8859-    do {
 8860-      do {
 8861-        x = jStat.randn();
 8862-        v = 1 + a2 * x;
 8863-      } while(v <= 0);
 8864-      v = v * v * v;
 8865-      u = Math.random();
 8866-    } while(u > 1 - 0.331 * Math.pow(x, 4) &&
 8867-    Math.log(u) > 0.5 * x*x + a1 * (1 - v + Math.log(v)));
 8868-    // alpha > 1
 8869-    if (shape == oalph)
 8870-      return a1 * v;
 8871-    // alpha < 1
 8872-    do {
 8873-      u = Math.random();
 8874-    } while(u === 0);
 8875-    return Math.pow(u, 1 / oalph) * a1 * v;
 8876-  };
 8877-
 8878-
 8879-// making use of static methods on the instance
 8880-  (function(funcs) {
 8881-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
 8882-      jStat.fn[passfunc] = function() {
 8883-        return jStat(
 8884-          jStat.map(this, function(value) { return jStat[passfunc](value); }));
 8885-      }
 8886-    })(funcs[i]);
 8887-  })('gammaln gammafn factorial factorialln'.split(' '));
 8888-
 8889-
 8890-  (function(funcs) {
 8891-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
 8892-      jStat.fn[passfunc] = function() {
 8893-        return jStat(jStat[passfunc].apply(null, arguments));
 8894-      };
 8895-    })(funcs[i]);
 8896-  })('randn'.split(' '));
 8897-
 8898-}(this.jStat, Math));
 8899-(function(jStat, Math) {
 8900-
 8901-// generate all distribution instance methods
 8902-  (function(list) {
 8903-    for (var i = 0; i < list.length; i++) (function(func) {
 8904-      // distribution instance method
 8905-      jStat[func] = function(a, b, c) {
 8906-        if (!(this instanceof arguments.callee))
 8907-          return new arguments.callee(a, b, c);
 8908-        this._a = a;
 8909-        this._b = b;
 8910-        this._c = c;
 8911-        return this;
 8912-      };
 8913-      // distribution method to be used on a jStat instance
 8914-      jStat.fn[func] = function(a, b, c) {
 8915-        var newthis = jStat[func](a, b, c);
 8916-        newthis.data = this;
 8917-        return newthis;
 8918-      };
 8919-      // sample instance method
 8920-      jStat[func].prototype.sample = function(arr) {
 8921-        var a = this._a;
 8922-        var b = this._b;
 8923-        var c = this._c;
 8924-        if (arr)
 8925-          return jStat.alter(arr, function() {
 8926-            return jStat[func].sample(a, b, c);
 8927-          });
 8928-        else
 8929-          return jStat[func].sample(a, b, c);
 8930-      };
 8931-      // generate the pdf, cdf and inv instance methods
 8932-      (function(vals) {
 8933-        for (var i = 0; i < vals.length; i++) (function(fnfunc) {
 8934-          jStat[func].prototype[fnfunc] = function(x) {
 8935-            var a = this._a;
 8936-            var b = this._b;
 8937-            var c = this._c;
 8938-            if (!x && x !== 0)
 8939-              x = this.data;
 8940-            if (typeof x !== 'number') {
 8941-              return jStat.fn.map.call(x, function(x) {
 8942-                return jStat[func][fnfunc](x, a, b, c);
 8943-              });
 8944-            }
 8945-            return jStat[func][fnfunc](x, a, b, c);
 8946-          };
 8947-        })(vals[i]);
 8948-      })('pdf cdf inv'.split(' '));
 8949-      // generate the mean, median, mode and variance instance methods
 8950-      (function(vals) {
 8951-        for (var i = 0; i < vals.length; i++) (function(fnfunc) {
 8952-          jStat[func].prototype[fnfunc] = function() {
 8953-            return jStat[func][fnfunc](this._a, this._b, this._c);
 8954-          };
 8955-        })(vals[i]);
 8956-      })('mean median mode variance'.split(' '));
 8957-    })(list[i]);
 8958-  })((
 8959-    'beta centralF cauchy chisquare exponential gamma invgamma kumaraswamy ' +
 8960-    'lognormal normal pareto studentt weibull uniform  binomial negbin hypgeom ' +
 8961-    'poisson triangular'
 8962-  ).split(' '));
 8963-
 8964-
 8965-
 8966-// extend beta function with static methods
 8967-  jStat.extend(jStat.beta, {
 8968-    pdf: function pdf(x, alpha, beta) {
 8969-      // PDF is zero outside the support
 8970-      if (x > 1 || x < 0)
 8971-        return 0;
 8972-      // PDF is one for the uniform case
 8973-      if (alpha == 1 && beta == 1)
 8974-        return 1;
 8975-
 8976-      if (alpha < 512 || beta < 512) {
 8977-        return (Math.pow(x, alpha - 1) * Math.pow(1 - x, beta - 1)) /
 8978-          jStat.betafn(alpha, beta);
 8979-      } else {
 8980-        return Math.exp((alpha - 1) * Math.log(x) +
 8981-          (beta - 1) * Math.log(1 - x) -
 8982-          jStat.betaln(alpha, beta));
 8983-      }
 8984-    },
 8985-
 8986-    cdf: function cdf(x, alpha, beta) {
 8987-      return (x > 1 || x < 0) ? (x > 1) * 1 : jStat.ibeta(x, alpha, beta);
 8988-    },
 8989-
 8990-    inv: function inv(x, alpha, beta) {
 8991-      return jStat.ibetainv(x, alpha, beta);
 8992-    },
 8993-
 8994-    mean: function mean(alpha, beta) {
 8995-      return alpha / (alpha + beta);
 8996-    },
 8997-
 8998-    median: function median(alpha, beta) {
 8999-      throw new Error('median not yet implemented');
 9000-    },
 9001-
 9002-    mode: function mode(alpha, beta) {
 9003-      return (alpha * beta) / (Math.pow(alpha + beta, 2) * (alpha + beta + 1));
 9004-    },
 9005-
 9006-    // return a random sample
 9007-    sample: function sample(alpha, beta) {
 9008-      var u = jStat.randg(alpha);
 9009-      return u / (u + jStat.randg(beta));
 9010-    },
 9011-
 9012-    variance: function variance(alpha, beta) {
 9013-      return (alpha * beta) / (Math.pow(alpha + beta, 2) * (alpha + beta + 1));
 9014-    }
 9015-  });
 9016-
 9017-// extend F function with static methods
 9018-  jStat.extend(jStat.centralF, {
 9019-    pdf: function pdf(x, df1, df2) {
 9020-      if (x < 0)
 9021-        return undefined;
 9022-      return Math.sqrt((Math.pow(df1 * x, df1) * Math.pow(df2, df2)) /
 9023-          (Math.pow(df1 * x + df2, df1 + df2))) /
 9024-        (x * jStat.betafn(df1/2, df2/2));
 9025-
 9026-    },
 9027-
 9028-    cdf: function cdf(x, df1, df2) {
 9029-      return jStat.ibeta((df1 * x) / (df1 * x + df2), df1 / 2, df2 / 2);
 9030-    },
 9031-
 9032-    inv: function inv(x, df1, df2) {
 9033-      return df2 / (df1 * (1 / jStat.ibetainv(x, df1 / 2, df2 / 2) - 1));
 9034-    },
 9035-
 9036-    mean: function mean(df1, df2) {
 9037-      return (df2 > 2) ? df2 / (df2 - 2) : undefined;
 9038-    },
 9039-
 9040-    mode: function mode(df1, df2) {
 9041-      return (df1 > 2) ? (df2 * (df1 - 2)) / (df1 * (df2 + 2)) : undefined;
 9042-    },
 9043-
 9044-    // return a random sample
 9045-    sample: function sample(df1, df2) {
 9046-      var x1 = jStat.randg(df1 / 2) * 2;
 9047-      var x2 = jStat.randg(df2 / 2) * 2;
 9048-      return (x1 / df1) / (x2 / df2);
 9049-    },
 9050-
 9051-    variance: function variance(df1, df2) {
 9052-      if (df2 <= 4)
 9053-        return undefined;
 9054-      return 2 * df2 * df2 * (df1 + df2 - 2) /
 9055-        (df1 * (df2 - 2) * (df2 - 2) * (df2 - 4));
 9056-    }
 9057-  });
 9058-
 9059-
 9060-// extend cauchy function with static methods
 9061-  jStat.extend(jStat.cauchy, {
 9062-    pdf: function pdf(x, local, scale) {
 9063-      return (scale / (Math.pow(x - local, 2) + Math.pow(scale, 2))) / Math.PI;
 9064-    },
 9065-
 9066-    cdf: function cdf(x, local, scale) {
 9067-      return Math.atan((x - local) / scale) / Math.PI + 0.5;
 9068-    },
 9069-
 9070-    inv: function(p, local, scale) {
 9071-      return local + scale * Math.tan(Math.PI * (p - 0.5));
 9072-    },
 9073-
 9074-    median: function median(local, scale) {
 9075-      return local;
 9076-    },
 9077-
 9078-    mode: function mode(local, scale) {
 9079-      return local;
 9080-    },
 9081-
 9082-    sample: function sample(local, scale) {
 9083-      return jStat.randn() *
 9084-        Math.sqrt(1 / (2 * jStat.randg(0.5))) * scale + local;
 9085-    }
 9086-  });
 9087-
 9088-
 9089-
 9090-// extend chisquare function with static methods
 9091-  jStat.extend(jStat.chisquare, {
 9092-    pdf: function pdf(x, dof) {
 9093-      return Math.exp((dof / 2 - 1) * Math.log(x) - x / 2 - (dof / 2) *
 9094-        Math.log(2) - jStat.gammaln(dof / 2));
 9095-    },
 9096-
 9097-    cdf: function cdf(x, dof) {
 9098-      return jStat.gammap(dof / 2, x / 2);
 9099-    },
 9100-
 9101-    inv: function(p, dof) {
 9102-      return 2 * jStat.gammapinv(p, 0.5 * dof);
 9103-    },
 9104-
 9105-    mean : function(dof) {
 9106-      return dof;
 9107-    },
 9108-
 9109-    // TODO: this is an approximation (is there a better way?)
 9110-    median: function median(dof) {
 9111-      return dof * Math.pow(1 - (2 / (9 * dof)), 3);
 9112-    },
 9113-
 9114-    mode: function mode(dof) {
 9115-      return (dof - 2 > 0) ? dof - 2 : 0;
 9116-    },
 9117-
 9118-    sample: function sample(dof) {
 9119-      return jStat.randg(dof / 2) * 2;
 9120-    },
 9121-
 9122-    variance: function variance(dof) {
 9123-      return 2 * dof;
 9124-    }
 9125-  });
 9126-
 9127-
 9128-
 9129-// extend exponential function with static methods
 9130-  jStat.extend(jStat.exponential, {
 9131-    pdf: function pdf(x, rate) {
 9132-      return x < 0 ? 0 : rate * Math.exp(-rate * x);
 9133-    },
 9134-
 9135-    cdf: function cdf(x, rate) {
 9136-      return x < 0 ? 0 : 1 - Math.exp(-rate * x);
 9137-    },
 9138-
 9139-    inv: function(p, rate) {
 9140-      return -Math.log(1 - p) / rate;
 9141-    },
 9142-
 9143-    mean : function(rate) {
 9144-      return 1 / rate;
 9145-    },
 9146-
 9147-    median: function (rate) {
 9148-      return (1 / rate) * Math.log(2);
 9149-    },
 9150-
 9151-    mode: function mode(rate) {
 9152-      return 0;
 9153-    },
 9154-
 9155-    sample: function sample(rate) {
 9156-      return -1 / rate * Math.log(Math.random());
 9157-    },
 9158-
 9159-    variance : function(rate) {
 9160-      return Math.pow(rate, -2);
 9161-    }
 9162-  });
 9163-
 9164-
 9165-
 9166-// extend gamma function with static methods
 9167-  jStat.extend(jStat.gamma, {
 9168-    pdf: function pdf(x, shape, scale) {
 9169-      return Math.exp((shape - 1) * Math.log(x) - x / scale -
 9170-        jStat.gammaln(shape) - shape * Math.log(scale));
 9171-    },
 9172-
 9173-    cdf: function cdf(x, shape, scale) {
 9174-      return jStat.gammap(shape, x / scale);
 9175-    },
 9176-
 9177-    inv: function(p, shape, scale) {
 9178-      return jStat.gammapinv(p, shape) * scale;
 9179-    },
 9180-
 9181-    mean : function(shape, scale) {
 9182-      return shape * scale;
 9183-    },
 9184-
 9185-    mode: function mode(shape, scale) {
 9186-      if(shape > 1) return (shape - 1) * scale;
 9187-      return undefined;
 9188-    },
 9189-
 9190-    sample: function sample(shape, scale) {
 9191-      return jStat.randg(shape) * scale;
 9192-    },
 9193-
 9194-    variance: function variance(shape, scale) {
 9195-      return shape * scale * scale;
 9196-    }
 9197-  });
 9198-
 9199-// extend inverse gamma function with static methods
 9200-  jStat.extend(jStat.invgamma, {
 9201-    pdf: function pdf(x, shape, scale) {
 9202-      return Math.exp(-(shape + 1) * Math.log(x) - scale / x -
 9203-        jStat.gammaln(shape) + shape * Math.log(scale));
 9204-    },
 9205-
 9206-    cdf: function cdf(x, shape, scale) {
 9207-      return 1 - jStat.gammap(shape, scale / x);
 9208-    },
 9209-
 9210-    inv: function(p, shape, scale) {
 9211-      return scale / jStat.gammapinv(1 - p, shape);
 9212-    },
 9213-
 9214-    mean : function(shape, scale) {
 9215-      return (shape > 1) ? scale / (shape - 1) : undefined;
 9216-    },
 9217-
 9218-    mode: function mode(shape, scale) {
 9219-      return scale / (shape + 1);
 9220-    },
 9221-
 9222-    sample: function sample(shape, scale) {
 9223-      return scale / jStat.randg(shape);
 9224-    },
 9225-
 9226-    variance: function variance(shape, scale) {
 9227-      if (shape <= 2)
 9228-        return undefined;
 9229-      return scale * scale / ((shape - 1) * (shape - 1) * (shape - 2));
 9230-    }
 9231-  });
 9232-
 9233-
 9234-// extend kumaraswamy function with static methods
 9235-  jStat.extend(jStat.kumaraswamy, {
 9236-    pdf: function pdf(x, alpha, beta) {
 9237-      return Math.exp(Math.log(alpha) + Math.log(beta) + (alpha - 1) *
 9238-        Math.log(x) + (beta - 1) *
 9239-        Math.log(1 - Math.pow(x, alpha)));
 9240-    },
 9241-
 9242-    cdf: function cdf(x, alpha, beta) {
 9243-      return (1 - Math.pow(1 - Math.pow(x, alpha), beta));
 9244-    },
 9245-
 9246-    mean : function(alpha, beta) {
 9247-      return (beta * jStat.gammafn(1 + 1 / alpha) *
 9248-        jStat.gammafn(beta)) / (jStat.gammafn(1 + 1 / alpha + beta));
 9249-    },
 9250-
 9251-    median: function median(alpha, beta) {
 9252-      return Math.pow(1 - Math.pow(2, -1 / beta), 1 / alpha);
 9253-    },
 9254-
 9255-    mode: function mode(alpha, beta) {
 9256-      if (!(alpha >= 1 && beta >= 1 && (alpha !== 1 && beta !== 1)))
 9257-        return undefined;
 9258-      return Math.pow((alpha - 1) / (alpha * beta - 1), 1 / alpha);
 9259-    },
 9260-
 9261-    variance: function variance(alpha, beta) {
 9262-      throw new Error('variance not yet implemented');
 9263-      // TODO: complete this
 9264-    }
 9265-  });
 9266-
 9267-
 9268-
 9269-// extend lognormal function with static methods
 9270-  jStat.extend(jStat.lognormal, {
 9271-    pdf: function pdf(x, mu, sigma) {
 9272-      return Math.exp(-Math.log(x) - 0.5 * Math.log(2 * Math.PI) -
 9273-        Math.log(sigma) - Math.pow(Math.log(x) - mu, 2) /
 9274-        (2 * sigma * sigma));
 9275-    },
 9276-
 9277-    cdf: function cdf(x, mu, sigma) {
 9278-      return 0.5 +
 9279-        (0.5 * jStat.erf((Math.log(x) - mu) / Math.sqrt(2 * sigma * sigma)));
 9280-    },
 9281-
 9282-    inv: function(p, mu, sigma) {
 9283-      return Math.exp(-1.41421356237309505 * sigma * jStat.erfcinv(2 * p) + mu);
 9284-    },
 9285-
 9286-    mean: function mean(mu, sigma) {
 9287-      return Math.exp(mu + sigma * sigma / 2);
 9288-    },
 9289-
 9290-    median: function median(mu, sigma) {
 9291-      return Math.exp(mu);
 9292-    },
 9293-
 9294-    mode: function mode(mu, sigma) {
 9295-      return Math.exp(mu - sigma * sigma);
 9296-    },
 9297-
 9298-    sample: function sample(mu, sigma) {
 9299-      return Math.exp(jStat.randn() * sigma + mu);
 9300-    },
 9301-
 9302-    variance: function variance(mu, sigma) {
 9303-      return (Math.exp(sigma * sigma) - 1) * Math.exp(2 * mu + sigma * sigma);
 9304-    }
 9305-  });
 9306-
 9307-
 9308-
 9309-// extend normal function with static methods
 9310-  jStat.extend(jStat.normal, {
 9311-    pdf: function pdf(x, mean, std) {
 9312-      return Math.exp(-0.5 * Math.log(2 * Math.PI) -
 9313-        Math.log(std) - Math.pow(x - mean, 2) / (2 * std * std));
 9314-    },
 9315-
 9316-    cdf: function cdf(x, mean, std) {
 9317-      return 0.5 * (1 + jStat.erf((x - mean) / Math.sqrt(2 * std * std)));
 9318-    },
 9319-
 9320-    inv: function(p, mean, std) {
 9321-      return -1.41421356237309505 * std * jStat.erfcinv(2 * p) + mean;
 9322-    },
 9323-
 9324-    mean : function(mean, std) {
 9325-      return mean;
 9326-    },
 9327-
 9328-    median: function median(mean, std) {
 9329-      return mean;
 9330-    },
 9331-
 9332-    mode: function (mean, std) {
 9333-      return mean;
 9334-    },
 9335-
 9336-    sample: function sample(mean, std) {
 9337-      return jStat.randn() * std + mean;
 9338-    },
 9339-
 9340-    variance : function(mean, std) {
 9341-      return std * std;
 9342-    }
 9343-  });
 9344-
 9345-
 9346-
 9347-// extend pareto function with static methods
 9348-  jStat.extend(jStat.pareto, {
 9349-    pdf: function pdf(x, scale, shape) {
 9350-      if (x <= scale)
 9351-        return undefined;
 9352-      return (shape * Math.pow(scale, shape)) / Math.pow(x, shape + 1);
 9353-    },
 9354-
 9355-    cdf: function cdf(x, scale, shape) {
 9356-      return 1 - Math.pow(scale / x, shape);
 9357-    },
 9358-
 9359-    mean: function mean(scale, shape) {
 9360-      if (shape <= 1)
 9361-        return undefined;
 9362-      return (shape * Math.pow(scale, shape)) / (shape - 1);
 9363-    },
 9364-
 9365-    median: function median(scale, shape) {
 9366-      return scale * (shape * Math.SQRT2);
 9367-    },
 9368-
 9369-    mode: function mode(scale, shape) {
 9370-      return scale;
 9371-    },
 9372-
 9373-    variance : function(scale, shape) {
 9374-      if (shape <= 2)
 9375-        return undefined;
 9376-      return (scale*scale * shape) / (Math.pow(shape - 1, 2) * (shape - 2));
 9377-    }
 9378-  });
 9379-
 9380-
 9381-
 9382-// extend studentt function with static methods
 9383-  jStat.extend(jStat.studentt, {
 9384-    pdf: function pdf(x, dof) {
 9385-      return (jStat.gammafn((dof + 1) / 2) / (Math.sqrt(dof * Math.PI) *
 9386-        jStat.gammafn(dof / 2))) *
 9387-        Math.pow(1 + ((x * x) / dof), -((dof + 1) / 2));
 9388-    },
 9389-
 9390-    cdf: function cdf(x, dof) {
 9391-      var dof2 = dof / 2;
 9392-      return jStat.ibeta((x + Math.sqrt(x * x + dof)) /
 9393-        (2 * Math.sqrt(x * x + dof)), dof2, dof2);
 9394-    },
 9395-
 9396-    inv: function(p, dof) {
 9397-      var x = jStat.ibetainv(2 * Math.min(p, 1 - p), 0.5 * dof, 0.5);
 9398-      x = Math.sqrt(dof * (1 - x) / x);
 9399-      return (p > 0) ? x : -x;
 9400-    },
 9401-
 9402-    mean: function mean(dof) {
 9403-      return (dof > 1) ? 0 : undefined;
 9404-    },
 9405-
 9406-    median: function median(dof) {
 9407-      return 0;
 9408-    },
 9409-
 9410-    mode: function mode(dof) {
 9411-      return 0;
 9412-    },
 9413-
 9414-    sample: function sample(dof) {
 9415-      return jStat.randn() * Math.sqrt(dof / (2 * jStat.randg(dof / 2)));
 9416-    },
 9417-
 9418-    variance: function variance(dof) {
 9419-      return (dof  > 2) ? dof / (dof - 2) : (dof > 1) ? Infinity : undefined;
 9420-    }
 9421-  });
 9422-
 9423-
 9424-
 9425-// extend weibull function with static methods
 9426-  jStat.extend(jStat.weibull, {
 9427-    pdf: function pdf(x, scale, shape) {
 9428-      if (x < 0)
 9429-        return 0;
 9430-      return (shape / scale) * Math.pow((x / scale), (shape - 1)) *
 9431-        Math.exp(-(Math.pow((x / scale), shape)));
 9432-    },
 9433-
 9434-    cdf: function cdf(x, scale, shape) {
 9435-      return x < 0 ? 0 : 1 - Math.exp(-Math.pow((x / scale), shape));
 9436-    },
 9437-
 9438-    inv: function(p, scale, shape) {
 9439-      return scale * Math.pow(-Math.log(1 - p), 1 / shape);
 9440-    },
 9441-
 9442-    mean : function(scale, shape) {
 9443-      return scale * jStat.gammafn(1 + 1 / shape);
 9444-    },
 9445-
 9446-    median: function median(scale, shape) {
 9447-      return scale * Math.pow(Math.log(2), 1 / shape);
 9448-    },
 9449-
 9450-    mode: function mode(scale, shape) {
 9451-      if (shape <= 1)
 9452-        return undefined;
 9453-      return scale * Math.pow((shape - 1) / shape, 1 / shape);
 9454-    },
 9455-
 9456-    sample: function sample(scale, shape) {
 9457-      return scale * Math.pow(-Math.log(Math.random()), 1 / shape);
 9458-    },
 9459-
 9460-    variance: function variance(scale, shape) {
 9461-      return scale * scale * jStat.gammafn(1 + 2 / shape) -
 9462-        Math.pow(this.mean(scale, shape), 2);
 9463-    }
 9464-  });
 9465-
 9466-
 9467-
 9468-// extend uniform function with static methods
 9469-  jStat.extend(jStat.uniform, {
 9470-    pdf: function pdf(x, a, b) {
 9471-      return (x < a || x > b) ? 0 : 1 / (b - a);
 9472-    },
 9473-
 9474-    cdf: function cdf(x, a, b) {
 9475-      if (x < a)
 9476-        return 0;
 9477-      else if (x < b)
 9478-        return (x - a) / (b - a);
 9479-      return 1;
 9480-    },
 9481-
 9482-    mean: function mean(a, b) {
 9483-      return 0.5 * (a + b);
 9484-    },
 9485-
 9486-    median: function median(a, b) {
 9487-      return jStat.mean(a, b);
 9488-    },
 9489-
 9490-    mode: function mode(a, b) {
 9491-      throw new Error('mode is not yet implemented');
 9492-    },
 9493-
 9494-    sample: function sample(a, b) {
 9495-      return (a / 2 + b / 2) + (b / 2 - a / 2) * (2 * Math.random() - 1);
 9496-    },
 9497-
 9498-    variance: function variance(a, b) {
 9499-      return Math.pow(b - a, 2) / 12;
 9500-    }
 9501-  });
 9502-
 9503-
 9504-
 9505-// extend uniform function with static methods
 9506-  jStat.extend(jStat.binomial, {
 9507-    pdf: function pdf(k, n, p) {
 9508-      return (p === 0 || p === 1) ?
 9509-        ((n * p) === k ? 1 : 0) :
 9510-      jStat.combination(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
 9511-    },
 9512-
 9513-    cdf: function cdf(x, n, p) {
 9514-      var binomarr = [],
 9515-        k = 0;
 9516-      if (x < 0) {
 9517-        return 0;
 9518-      }
 9519-      if (x < n) {
 9520-        for (; k <= x; k++) {
 9521-          binomarr[ k ] = jStat.binomial.pdf(k, n, p);
 9522-        }
 9523-        return jStat.sum(binomarr);
 9524-      }
 9525-      return 1;
 9526-    }
 9527-  });
 9528-
 9529-
 9530-
 9531-// extend uniform function with static methods
 9532-  jStat.extend(jStat.negbin, {
 9533-    pdf: function pdf(k, r, p) {
 9534-      return k !== k | 0
 9535-        ? false
 9536-        : k < 0
 9537-        ? 0
 9538-        : jStat.combination(k + r - 1, r - 1) * Math.pow(1 - p, k) * Math.pow(p, r);
 9539-    },
 9540-
 9541-    cdf: function cdf(x, r, p) {
 9542-      var sum = 0,
 9543-        k = 0;
 9544-      if (x < 0) return 0;
 9545-      for (; k <= x; k++) {
 9546-        sum += jStat.negbin.pdf(k, r, p);
 9547-      }
 9548-      return sum;
 9549-    }
 9550-  });
 9551-
 9552-
 9553-
 9554-// extend uniform function with static methods
 9555-  jStat.extend(jStat.hypgeom, {
 9556-    pdf: function pdf(k, N, m, n) {
 9557-      // Hypergeometric PDF.
 9558-
 9559-      // A simplification of the CDF algorithm below.
 9560-
 9561-      // k = number of successes drawn
 9562-      // N = population size
 9563-      // m = number of successes in population
 9564-      // n = number of items drawn from population
 9565-
 9566-      if(k !== k | 0) {
 9567-        return false;
 9568-      } else if(k < 0 || k < m - (N - n)) {
 9569-        // It's impossible to have this few successes drawn.
 9570-        return 0;
 9571-      } else if(k > n || k > m) {
 9572-        // It's impossible to have this many successes drawn.
 9573-        return 0;
 9574-      } else if (m * 2 > N) {
 9575-        // More than half the population is successes.
 9576-
 9577-        if(n * 2 > N) {
 9578-          // More than half the population is sampled.
 9579-
 9580-          return jStat.hypgeom.pdf(N - m - n + k, N, N - m, N - n)
 9581-        } else {
 9582-          // Half or less of the population is sampled.
 9583-
 9584-          return jStat.hypgeom.pdf(n - k, N, N - m, n);
 9585-        }
 9586-
 9587-      } else if(n * 2 > N) {
 9588-        // Half or less is successes.
 9589-
 9590-        return jStat.hypgeom.pdf(m - k, N, m, N - n);
 9591-
 9592-      } else if(m < n) {
 9593-        // We want to have the number of things sampled to be less than the
 9594-        // successes available. So swap the definitions of successful and sampled.
 9595-        return jStat.hypgeom.pdf(k, N, n, m);
 9596-      } else {
 9597-        // If we get here, half or less of the population was sampled, half or
 9598-        // less of it was successes, and we had fewer sampled things than
 9599-        // successes. Now we can do this complicated iterative algorithm in an
 9600-        // efficient way.
 9601-
 9602-        // The basic premise of the algorithm is that we partially normalize our
 9603-        // intermediate product to keep it in a numerically good region, and then
 9604-        // finish the normalization at the end.
 9605-
 9606-        // This variable holds the scaled probability of the current number of
 9607-        // successes.
 9608-        var scaledPDF = 1;
 9609-
 9610-        // This keeps track of how much we have normalized.
 9611-        var samplesDone = 0;
 9612-
 9613-        for(var i = 0; i < k; i++) {
 9614-          // For every possible number of successes up to that observed...
 9615-
 9616-          while(scaledPDF > 1 && samplesDone < n) {
 9617-            // Intermediate result is growing too big. Apply some of the
 9618-            // normalization to shrink everything.
 9619-
 9620-            scaledPDF *= 1 - (m / (N - samplesDone));
 9621-
 9622-            // Say we've normalized by this sample already.
 9623-            samplesDone++;
 9624-          }
 9625-
 9626-          // Work out the partially-normalized hypergeometric PDF for the next
 9627-          // number of successes
 9628-          scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1));
 9629-        }
 9630-
 9631-        for(; samplesDone < n; samplesDone++) {
 9632-          // Apply all the rest of the normalization
 9633-          scaledPDF *= 1 - (m / (N - samplesDone));
 9634-        }
 9635-
 9636-        // Bound answer sanely before returning.
 9637-        return Math.min(1, Math.max(0, scaledPDF));
 9638-      }
 9639-    },
 9640-
 9641-    cdf: function cdf(x, N, m, n) {
 9642-      // Hypergeometric CDF.
 9643-
 9644-      // This algorithm is due to Prof. Thomas S. Ferguson, <[email protected]>,
 9645-      // and comes from his hypergeometric test calculator at
 9646-      // <http://www.math.ucla.edu/~tom/distributions/Hypergeometric.html>.
 9647-
 9648-      // x = number of successes drawn
 9649-      // N = population size
 9650-      // m = number of successes in population
 9651-      // n = number of items drawn from population
 9652-
 9653-      if(x < 0 || x < m - (N - n)) {
 9654-        // It's impossible to have this few successes drawn or fewer.
 9655-        return 0;
 9656-      } else if(x >= n || x >= m) {
 9657-        // We will always have this many successes or fewer.
 9658-        return 1;
 9659-      } else if (m * 2 > N) {
 9660-        // More than half the population is successes.
 9661-
 9662-        if(n * 2 > N) {
 9663-          // More than half the population is sampled.
 9664-
 9665-          return jStat.hypgeom.cdf(N - m - n + x, N, N - m, N - n)
 9666-        } else {
 9667-          // Half or less of the population is sampled.
 9668-
 9669-          return 1 - jStat.hypgeom.cdf(n - x - 1, N, N - m, n);
 9670-        }
 9671-
 9672-      } else if(n * 2 > N) {
 9673-        // Half or less is successes.
 9674-
 9675-        return 1 - jStat.hypgeom.cdf(m - x - 1, N, m, N - n);
 9676-
 9677-      } else if(m < n) {
 9678-        // We want to have the number of things sampled to be less than the
 9679-        // successes available. So swap the definitions of successful and sampled.
 9680-        return jStat.hypgeom.cdf(x, N, n, m);
 9681-      } else {
 9682-        // If we get here, half or less of the population was sampled, half or
 9683-        // less of it was successes, and we had fewer sampled things than
 9684-        // successes. Now we can do this complicated iterative algorithm in an
 9685-        // efficient way.
 9686-
 9687-        // The basic premise of the algorithm is that we partially normalize our
 9688-        // intermediate sum to keep it in a numerically good region, and then
 9689-        // finish the normalization at the end.
 9690-
 9691-        // Holds the intermediate, scaled total CDF.
 9692-        var scaledCDF = 1;
 9693-
 9694-        // This variable holds the scaled probability of the current number of
 9695-        // successes.
 9696-        var scaledPDF = 1;
 9697-
 9698-        // This keeps track of how much we have normalized.
 9699-        var samplesDone = 0;
 9700-
 9701-        for(var i = 0; i < x; i++) {
 9702-          // For every possible number of successes up to that observed...
 9703-
 9704-          while(scaledCDF > 1 && samplesDone < n) {
 9705-            // Intermediate result is growing too big. Apply some of the
 9706-            // normalization to shrink everything.
 9707-
 9708-            var factor = 1 - (m / (N - samplesDone));
 9709-
 9710-            scaledPDF *= factor;
 9711-            scaledCDF *= factor;
 9712-
 9713-            // Say we've normalized by this sample already.
 9714-            samplesDone++;
 9715-          }
 9716-
 9717-          // Work out the partially-normalized hypergeometric PDF for the next
 9718-          // number of successes
 9719-          scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1));
 9720-
 9721-          // Add to the CDF answer.
 9722-          scaledCDF += scaledPDF;
 9723-        }
 9724-
 9725-        for(; samplesDone < n; samplesDone++) {
 9726-          // Apply all the rest of the normalization
 9727-          scaledCDF *= 1 - (m / (N - samplesDone));
 9728-        }
 9729-
 9730-        // Bound answer sanely before returning.
 9731-        return Math.min(1, Math.max(0, scaledCDF));
 9732-      }
 9733-    }
 9734-  });
 9735-
 9736-
 9737-
 9738-// extend uniform function with static methods
 9739-  jStat.extend(jStat.poisson, {
 9740-    pdf: function pdf(k, l) {
 9741-      return Math.pow(l, k) * Math.exp(-l) / jStat.factorial(k);
 9742-    },
 9743-
 9744-    cdf: function cdf(x, l) {
 9745-      var sumarr = [],
 9746-        k = 0;
 9747-      if (x < 0) return 0;
 9748-      for (; k <= x; k++) {
 9749-        sumarr.push(jStat.poisson.pdf(k, l));
 9750-      }
 9751-      return jStat.sum(sumarr);
 9752-    },
 9753-
 9754-    mean : function(l) {
 9755-      return l;
 9756-    },
 9757-
 9758-    variance : function(l) {
 9759-      return l;
 9760-    },
 9761-
 9762-    sample: function sample(l) {
 9763-      var p = 1, k = 0, L = Math.exp(-l);
 9764-      do {
 9765-        k++;
 9766-        p *= Math.random();
 9767-      } while (p > L);
 9768-      return k - 1;
 9769-    }
 9770-  });
 9771-
 9772-// extend triangular function with static methods
 9773-  jStat.extend(jStat.triangular, {
 9774-    pdf: function pdf(x, a, b, c) {
 9775-      return (b <= a || c < a || c > b)
 9776-        ? undefined
 9777-        : (x < a || x > b)
 9778-        ? 0
 9779-        : (x <= c)
 9780-        ? (2 * (x - a)) / ((b - a) * (c - a))
 9781-        : (2 * (b - x)) / ((b - a) * (b - c));
 9782-    },
 9783-
 9784-    cdf: function cdf(x, a, b, c) {
 9785-      if (b <= a || c < a || c > b)
 9786-        return undefined;
 9787-      if (x < a) {
 9788-        return 0;
 9789-      } else {
 9790-        if (x <= c)
 9791-          return Math.pow(x - a, 2) / ((b - a) * (c - a));
 9792-        return 1 - Math.pow(b - x, 2) / ((b - a) * (b - c));
 9793-      }
 9794-      // never reach this
 9795-      return 1;
 9796-    },
 9797-
 9798-    mean: function mean(a, b, c) {
 9799-      return (a + b + c) / 3;
 9800-    },
 9801-
 9802-    median: function median(a, b, c) {
 9803-      if (c <= (a + b) / 2) {
 9804-        return b - Math.sqrt((b - a) * (b - c)) / Math.sqrt(2);
 9805-      } else if (c > (a + b) / 2) {
 9806-        return a + Math.sqrt((b - a) * (c - a)) / Math.sqrt(2);
 9807-      }
 9808-    },
 9809-
 9810-    mode: function mode(a, b, c) {
 9811-      return c;
 9812-    },
 9813-
 9814-    sample: function sample(a, b, c) {
 9815-      var u = Math.random();
 9816-      if (u < ((c - a) / (b - a)))
 9817-        return a + Math.sqrt(u * (b - a) * (c - a))
 9818-      return b - Math.sqrt((1 - u) * (b - a) * (b - c));
 9819-    },
 9820-
 9821-    variance: function variance(a, b, c) {
 9822-      return (a * a + b * b + c * c - a * b - a * c - b * c) / 18;
 9823-    }
 9824-  });
 9825-
 9826-}(this.jStat, Math));
 9827-/* Provides functions for the solution of linear system of equations, integration, extrapolation,
 9828- * interpolation, eigenvalue problems, differential equations and PCA analysis. */
 9829-
 9830-(function(jStat, Math) {
 9831-
 9832-  var push = Array.prototype.push;
 9833-  var isArray = jStat.utils.isArray;
 9834-
 9835-  jStat.extend({
 9836-
 9837-    // add a vector/matrix to a vector/matrix or scalar
 9838-    add: function add(arr, arg) {
 9839-      // check if arg is a vector or scalar
 9840-      if (isArray(arg)) {
 9841-        if (!isArray(arg[0])) arg = [ arg ];
 9842-        return jStat.map(arr, function(value, row, col) {
 9843-          return value + arg[row][col];
 9844-        });
 9845-      }
 9846-      return jStat.map(arr, function(value) { return value + arg; });
 9847-    },
 9848-
 9849-    // subtract a vector or scalar from the vector
 9850-    subtract: function subtract(arr, arg) {
 9851-      // check if arg is a vector or scalar
 9852-      if (isArray(arg)) {
 9853-        if (!isArray(arg[0])) arg = [ arg ];
 9854-        return jStat.map(arr, function(value, row, col) {
 9855-          return value - arg[row][col] || 0;
 9856-        });
 9857-      }
 9858-      return jStat.map(arr, function(value) { return value - arg; });
 9859-    },
 9860-
 9861-    // matrix division
 9862-    divide: function divide(arr, arg) {
 9863-      if (isArray(arg)) {
 9864-        if (!isArray(arg[0])) arg = [ arg ];
 9865-        return jStat.multiply(arr, jStat.inv(arg));
 9866-      }
 9867-      return jStat.map(arr, function(value) { return value / arg; });
 9868-    },
 9869-
 9870-    // matrix multiplication
 9871-    multiply: function multiply(arr, arg) {
 9872-      var row, col, nrescols, sum,
 9873-        nrow = arr.length,
 9874-        ncol = arr[0].length,
 9875-        res = jStat.zeros(nrow, nrescols = (isArray(arg)) ? arg[0].length : ncol),
 9876-        rescols = 0;
 9877-      if (isArray(arg)) {
 9878-        for (; rescols < nrescols; rescols++) {
 9879-          for (row = 0; row < nrow; row++) {
 9880-            sum = 0;
 9881-            for (col = 0; col < ncol; col++)
 9882-              sum += arr[row][col] * arg[col][rescols];
 9883-            res[row][rescols] = sum;
 9884-          }
 9885-        }
 9886-        return (nrow === 1 && rescols === 1) ? res[0][0] : res;
 9887-      }
 9888-      return jStat.map(arr, function(value) { return value * arg; });
 9889-    },
 9890-
 9891-    // Returns the dot product of two matricies
 9892-    dot: function dot(arr, arg) {
 9893-      if (!isArray(arr[0])) arr = [ arr ];
 9894-      if (!isArray(arg[0])) arg = [ arg ];
 9895-      // convert column to row vector
 9896-      var left = (arr[0].length === 1 && arr.length !== 1) ? jStat.transpose(arr) : arr,
 9897-        right = (arg[0].length === 1 && arg.length !== 1) ? jStat.transpose(arg) : arg,
 9898-        res = [],
 9899-        row = 0,
 9900-        nrow = left.length,
 9901-        ncol = left[0].length,
 9902-        sum, col;
 9903-      for (; row < nrow; row++) {
 9904-        res[row] = [];
 9905-        sum = 0;
 9906-        for (col = 0; col < ncol; col++)
 9907-          sum += left[row][col] * right[row][col];
 9908-        res[row] = sum;
 9909-      }
 9910-      return (res.length === 1) ? res[0] : res;
 9911-    },
 9912-
 9913-    // raise every element by a scalar
 9914-    pow: function pow(arr, arg) {
 9915-      return jStat.map(arr, function(value) { return Math.pow(value, arg); });
 9916-    },
 9917-
 9918-    // generate the absolute values of the vector
 9919-    abs: function abs(arr) {
 9920-      return jStat.map(arr, function(value) { return Math.abs(value); });
 9921-    },
 9922-
 9923-    // TODO: make compatible with matrices
 9924-    // computes the p-norm of the vector
 9925-    norm: function norm(arr, p) {
 9926-      var nnorm = 0,
 9927-        i = 0;
 9928-      // check the p-value of the norm, and set for most common case
 9929-      if (isNaN(p)) p = 2;
 9930-      // check if multi-dimensional array, and make vector correction
 9931-      if (isArray(arr[0])) arr = arr[0];
 9932-      // vector norm
 9933-      for (; i < arr.length; i++) {
 9934-        nnorm += Math.pow(Math.abs(arr[i]), p);
 9935-      }
 9936-      return Math.pow(nnorm, 1 / p);
 9937-    },
 9938-
 9939-    // TODO: make compatible with matrices
 9940-    // computes the angle between two vectors in rads
 9941-    angle: function angle(arr, arg) {
 9942-      return Math.acos(jStat.dot(arr, arg) / (jStat.norm(arr) * jStat.norm(arg)));
 9943-    },
 9944-
 9945-    // augment one matrix by another
 9946-    aug: function aug(a, b) {
 9947-      var newarr = a.slice(),
 9948-        i = 0;
 9949-      for (; i < newarr.length; i++) {
 9950-        push.apply(newarr[i], b[i]);
 9951-      }
 9952-      return newarr;
 9953-    },
 9954-
 9955-    inv: function inv(a) {
 9956-      var rows = a.length,
 9957-        cols = a[0].length,
 9958-        b = jStat.identity(rows, cols),
 9959-        c = jStat.gauss_jordan(a, b),
 9960-        obj = [],
 9961-        i = 0,
 9962-        j;
 9963-      for (; i < rows; i++) {
 9964-        obj[i] = [];
 9965-        for (j = cols - 1; j < c[0].length; j++)
 9966-          obj[i][j - cols] = c[i][j];
 9967-      }
 9968-      return obj;
 9969-    },
 9970-
 9971-    // calculate the determinant of a matrix
 9972-    det: function det(a) {
 9973-      var alen = a.length,
 9974-        alend = alen * 2,
 9975-        vals = new Array(alend),
 9976-        rowshift = alen - 1,
 9977-        colshift = alend - 1,
 9978-        mrow = rowshift - alen + 1,
 9979-        mcol = colshift,
 9980-        i = 0,
 9981-        result = 0,
 9982-        j;
 9983-      // check for special 2x2 case
 9984-      if (alen === 2) {
 9985-        return a[0][0] * a[1][1] - a[0][1] * a[1][0];
 9986-      }
 9987-      for (; i < alend; i++) {
 9988-        vals[i] = 1;
 9989-      }
 9990-      for (i = 0; i < alen; i++) {
 9991-        for (j = 0; j < alen; j++) {
 9992-          vals[(mrow < 0) ? mrow + alen : mrow ] *= a[i][j];
 9993-          vals[(mcol < alen) ? mcol + alen : mcol ] *= a[i][j];
 9994-          mrow++;
 9995-          mcol--;
 9996-        }
 9997-        mrow = --rowshift - alen + 1;
 9998-        mcol = --colshift;
 9999-      }
10000-      for (i = 0; i < alen; i++) {
10001-        result += vals[i];
10002-      }
10003-      for (; i < alend; i++) {
10004-        result -= vals[i];
10005-      }
10006-      return result;
10007-    },
10008-
10009-    gauss_elimination: function gauss_elimination(a, b) {
10010-      var i = 0,
10011-        j = 0,
10012-        n = a.length,
10013-        m = a[0].length,
10014-        factor = 1,
10015-        sum = 0,
10016-        x = [],
10017-        maug, pivot, temp, k;
10018-      a = jStat.aug(a, b);
10019-      maug = a[0].length;
10020-      for(; i < n; i++) {
10021-        pivot = a[i][i];
10022-        j = i;
10023-        for (k = i + 1; k < m; k++) {
10024-          if (pivot < Math.abs(a[k][i])) {
10025-            pivot = a[k][i];
10026-            j = k;
10027-          }
10028-        }
10029-        if (j != i) {
10030-          for(k = 0; k < maug; k++) {
10031-            temp = a[i][k];
10032-            a[i][k] = a[j][k];
10033-            a[j][k] = temp;
10034-          }
10035-        }
10036-        for (j = i + 1; j < n; j++) {
10037-          factor = a[j][i] / a[i][i];
10038-          for(k = i; k < maug; k++) {
10039-            a[j][k] = a[j][k] - factor * a[i][k];
10040-          }
10041-        }
10042-      }
10043-      for (i = n - 1; i >= 0; i--) {
10044-        sum = 0;
10045-        for (j = i + 1; j<= n - 1; j++) {
10046-          sum = x[j] * a[i][j];
10047-        }
10048-        x[i] =(a[i][maug - 1] - sum) / a[i][i];
10049-      }
10050-      return x;
10051-    },
10052-
10053-    gauss_jordan: function gauss_jordan(a, b) {
10054-      var m = jStat.aug(a, b),
10055-        h = m.length,
10056-        w = m[0].length;
10057-      // find max pivot
10058-      for (var y = 0; y < h; y++) {
10059-        var maxrow = y;
10060-        for (var y2 = y+1; y2 < h; y2++) {
10061-          if (Math.abs(m[y2][y]) > Math.abs(m[maxrow][y]))
10062-            maxrow = y2;
10063-        }
10064-        var tmp = m[y];
10065-        m[y] = m[maxrow];
10066-        m[maxrow] = tmp
10067-        for (var y2 = y+1; y2 < h; y2++) {
10068-          c = m[y2][y] / m[y][y];
10069-          for (var x = y; x < w; x++) {
10070-            m[y2][x] -= m[y][x] * c;
10071-          }
10072-        }
10073-      }
10074-      // backsubstitute
10075-      for (var y = h-1; y >= 0; y--) {
10076-        c = m[y][y];
10077-        for (var y2 = 0; y2 < y; y2++) {
10078-          for (var x = w-1; x > y-1; x--) {
10079-            m[y2][x] -= m[y][x] * m[y2][y] / c;
10080-          }
10081-        }
10082-        m[y][y] /= c;
10083-        for (var x = h; x < w; x++) {
10084-          m[y][x] /= c;
10085-        }
10086-      }
10087-      return m;
10088-    },
10089-
10090-    lu: function lu(a, b) {
10091-      throw new Error('lu not yet implemented');
10092-    },
10093-
10094-    cholesky: function cholesky(a, b) {
10095-      throw new Error('cholesky not yet implemented');
10096-    },
10097-
10098-    gauss_jacobi: function gauss_jacobi(a, b, x, r) {
10099-      var i = 0;
10100-      var j = 0;
10101-      var n = a.length;
10102-      var l = [];
10103-      var u = [];
10104-      var d = [];
10105-      var xv, c, h, xk;
10106-      for (; i < n; i++) {
10107-        l[i] = [];
10108-        u[i] = [];
10109-        d[i] = [];
10110-        for (j = 0; j < n; j++) {
10111-          if (i > j) {
10112-            l[i][j] = a[i][j];
10113-            u[i][j] = d[i][j] = 0;
10114-          } else if (i < j) {
10115-            u[i][j] = a[i][j];
10116-            l[i][j] = d[i][j] = 0;
10117-          } else {
10118-            d[i][j] = a[i][j];
10119-            l[i][j] = u[i][j] = 0;
10120-          }
10121-        }
10122-      }
10123-      h = jStat.multiply(jStat.multiply(jStat.inv(d), jStat.add(l, u)), -1);
10124-      c = jStat.multiply(jStat.inv(d), b);
10125-      xv = x;
10126-      xk = jStat.add(jStat.multiply(h, x), c);
10127-      i = 2;
10128-      while (Math.abs(jStat.norm(jStat.subtract(xk,xv))) > r) {
10129-        xv = xk;
10130-        xk = jStat.add(jStat.multiply(h, xv), c);
10131-        i++;
10132-      }
10133-      return xk;
10134-    },
10135-
10136-    gauss_seidel: function gauss_seidel(a, b, x, r) {
10137-      var i = 0;
10138-      var n = a.length;
10139-      var l = [];
10140-      var u = [];
10141-      var d = [];
10142-      var j, xv, c, h, xk;
10143-      for (; i < n; i++) {
10144-        l[i] = [];
10145-        u[i] = [];
10146-        d[i] = [];
10147-        for (j = 0; j < n; j++) {
10148-          if (i > j) {
10149-            l[i][j] = a[i][j];
10150-            u[i][j] = d[i][j] = 0;
10151-          } else if (i < j) {
10152-            u[i][j] = a[i][j];
10153-            l[i][j] = d[i][j] = 0;
10154-          } else {
10155-            d[i][j] = a[i][j];
10156-            l[i][j] = u[i][j] = 0;
10157-          }
10158-        }
10159-      }
10160-      h = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d, l)), u), -1);
10161-      c = jStat.multiply(jStat.inv(jStat.add(d, l)), b);
10162-      xv = x;
10163-      xk = jStat.add(jStat.multiply(h, x), c);
10164-      i = 2;
10165-      while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {
10166-        xv = xk;
10167-        xk = jStat.add(jStat.multiply(h, xv), c);
10168-        i = i + 1;
10169-      }
10170-      return xk;
10171-    },
10172-
10173-    SOR: function SOR(a, b, x, r, w) {
10174-      var i = 0;
10175-      var n = a.length;
10176-      var l = [];
10177-      var u = [];
10178-      var d = [];
10179-      var j, xv, c, h, xk;
10180-      for (; i < n; i++) {
10181-        l[i] = [];
10182-        u[i] = [];
10183-        d[i] = [];
10184-        for (j = 0; j < n; j++) {
10185-          if (i > j) {
10186-            l[i][j] = a[i][j];
10187-            u[i][j] = d[i][j] = 0;
10188-          } else if (i < j) {
10189-            u[i][j] = a[i][j];
10190-            l[i][j] = d[i][j] = 0;
10191-          } else {
10192-            d[i][j] = a[i][j];
10193-            l[i][j] = u[i][j] = 0;
10194-          }
10195-        }
10196-      }
10197-      h = jStat.multiply(jStat.inv(jStat.add(d, jStat.multiply(l, w))),
10198-        jStat.subtract(jStat.multiply(d, 1 - w),
10199-          jStat.multiply(u, w)));
10200-      c = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d,
10201-        jStat.multiply(l, w))), b), w);
10202-      xv = x;
10203-      xk = jStat.add(jStat.multiply(h, x), c);
10204-      i = 2;
10205-      while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {
10206-        xv = xk;
10207-        xk = jStat.add(jStat.multiply(h, xv), c);
10208-        i++;
10209-      }
10210-      return xk;
10211-    },
10212-
10213-    householder: function householder(a) {
10214-      var m = a.length;
10215-      var n = a[0].length;
10216-      var i = 0;
10217-      var w = [];
10218-      var p = [];
10219-      var alpha, r, k, j, factor;
10220-      for (; i < m - 1; i++) {
10221-        alpha = 0;
10222-        for (j = i + 1; j < n; j++)
10223-          alpha += (a[j][i] * a[j][i]);
10224-        factor = (a[i + 1][i] > 0) ? -1 : 1;
10225-        alpha = factor * Math.sqrt(alpha);
10226-        r = Math.sqrt((((alpha * alpha) - a[i + 1][i] * alpha) / 2));
10227-        w = jStat.zeros(m, 1);
10228-        w[i + 1][0] = (a[i + 1][i] - alpha) / (2 * r);
10229-        for (k = i + 2; k < m; k++) w[k][0] = a[k][i] / (2 * r);
10230-        p = jStat.subtract(jStat.identity(m, n),
10231-          jStat.multiply(jStat.multiply(w, jStat.transpose(w)), 2));
10232-        a = jStat.multiply(p, jStat.multiply(a, p));
10233-      }
10234-      return a;
10235-    },
10236-
10237-    // TODO: not working properly.
10238-    QR: function QR(a, b) {
10239-      var m = a.length;
10240-      var n = a[0].length;
10241-      var i = 0;
10242-      var w = [];
10243-      var p = [];
10244-      var x = [];
10245-      var j, alpha, r, k, factor, sum;
10246-      for (; i < m - 1; i++) {
10247-        alpha = 0;
10248-        for (j = i + 1; j < n; j++)
10249-          alpha += (a[j][i] * a[j][i]);
10250-        factor = (a[i + 1][i] > 0) ? -1 : 1;
10251-        alpha = factor * Math.sqrt(alpha);
10252-        r = Math.sqrt((((alpha * alpha) - a[i + 1][i] * alpha) / 2));
10253-        w = jStat.zeros(m, 1);
10254-        w[i + 1][0] = (a[i + 1][i] - alpha) / (2 * r);
10255-        for (k = i + 2; k < m; k++)
10256-          w[k][0] = a[k][i] / (2 * r);
10257-        p = jStat.subtract(jStat.identity(m, n),
10258-          jStat.multiply(jStat.multiply(w, jStat.transpose(w)), 2));
10259-        a = jStat.multiply(p, a);
10260-        b = jStat.multiply(p, b);
10261-      }
10262-      for (i = m - 1; i >= 0; i--) {
10263-        sum = 0;
10264-        for (j = i + 1; j <= n - 1; j++)
10265-          sum = x[j] * a[i][j];
10266-        x[i] = b[i][0] / a[i][i];
10267-      }
10268-      return x;
10269-    },
10270-
10271-    jacobi: function jacobi(a) {
10272-      var condition = 1;
10273-      var count = 0;
10274-      var n = a.length;
10275-      var e = jStat.identity(n, n);
10276-      var ev = [];
10277-      var b, i, j, p, q, maxim, theta, s;
10278-      // condition === 1 only if tolerance is not reached
10279-      while (condition === 1) {
10280-        count++;
10281-        maxim = a[0][1];
10282-        p = 0;
10283-        q = 1;
10284-        for (i = 0; i < n; i++) {
10285-          for (j = 0; j < n; j++) {
10286-            if (i != j) {
10287-              if (maxim < Math.abs(a[i][j])) {
10288-                maxim = Math.abs(a[i][j]);
10289-                p = i;
10290-                q = j;
10291-              }
10292-            }
10293-          }
10294-        }
10295-        if (a[p][p] === a[q][q])
10296-          theta = (a[p][q] > 0) ? Math.PI / 4 : -Math.PI / 4;
10297-        else
10298-          theta = Math.atan(2 * a[p][q] / (a[p][p] - a[q][q])) / 2;
10299-        s = jStat.identity(n, n);
10300-        s[p][p] = Math.cos(theta);
10301-        s[p][q] = -Math.sin(theta);
10302-        s[q][p] = Math.sin(theta);
10303-        s[q][q] = Math.cos(theta);
10304-        // eigen vector matrix
10305-        e = jStat.multiply(e, s);
10306-        b = jStat.multiply(jStat.multiply(jStat.inv(s), a), s);
10307-        a = b;
10308-        condition = 0;
10309-        for (i = 1; i < n; i++) {
10310-          for (j = 1; j < n; j++) {
10311-            if (i != j && Math.abs(a[i][j]) > 0.001) {
10312-              condition = 1;
10313-            }
10314-          }
10315-        }
10316-      }
10317-      for (i = 0; i < n; i++) ev.push(a[i][i]);
10318-      //returns both the eigenvalue and eigenmatrix
10319-      return [e, ev];
10320-    },
10321-
10322-    rungekutta: function rungekutta(f, h, p, t_j, u_j, order) {
10323-      var k1, k2, u_j1, k3, k4;
10324-      if (order === 2) {
10325-        while (t_j <= p) {
10326-          k1 = h * f(t_j, u_j);
10327-          k2 = h * f(t_j + h, u_j + k1);
10328-          u_j1 = u_j + (k1 + k2) / 2;
10329-          u_j = u_j1;
10330-          t_j = t_j + h;
10331-        }
10332-      }
10333-      if (order === 4) {
10334-        while (t_j <= p) {
10335-          k1 = h * f(t_j, u_j);
10336-          k2 = h * f(t_j + h / 2, u_j + k1 / 2);
10337-          k3 = h * f(t_j + h / 2, u_j + k2 / 2);
10338-          k4 = h * f(t_j +h, u_j + k3);
10339-          u_j1 = u_j + (k1 + 2 * k2 + 2 * k3 + k4) / 6;
10340-          u_j = u_j1;
10341-          t_j = t_j + h;
10342-        }
10343-      }
10344-      return u_j;
10345-    },
10346-
10347-    romberg: function romberg(f, a, b, order) {
10348-      var i = 0;
10349-      var h = (b - a) / 2;
10350-      var x = [];
10351-      var h1 = [];
10352-      var g = [];
10353-      var m, a1, j, k, I, d;
10354-      while (i < order / 2) {
10355-        I = f(a);
10356-        for (j = a, k = 0; j <= b; j = j + h, k++) x[k] = j;
10357-        m = x.length;
10358-        for (j = 1; j < m - 1; j++) {
10359-          I += (((j % 2) !== 0) ? 4 : 2) * f(x[j]);
10360-        }
10361-        I = (h / 3) * (I + f(b));
10362-        g[i] = I;
10363-        h /= 2;
10364-        i++;
10365-      }
10366-      a1 = g.length;
10367-      m = 1;
10368-      while (a1 !== 1) {
10369-        for (j = 0; j < a1 - 1; j++)
10370-          h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);
10371-        a1 = h1.length;
10372-        g = h1;
10373-        h1 = [];
10374-        m++;
10375-      }
10376-      return g;
10377-    },
10378-
10379-    richardson: function richardson(X, f, x, h) {
10380-      function pos(X, x) {
10381-        var i = 0;
10382-        var n = X.length;
10383-        var p;
10384-        for (; i < n; i++)
10385-          if (X[i] === x) p = i;
10386-        return p;
10387-      }
10388-      var n = X.length,
10389-        h_min = Math.abs(x - X[pos(X, x) + 1]),
10390-        i = 0,
10391-        g = [],
10392-        h1 = [],
10393-        y1, y2, m, a, j;
10394-      while (h >= h_min) {
10395-        y1 = pos(X, x + h);
10396-        y2 = pos(X, x);
10397-        g[i] = (f[y1] - 2 * f[y2] + f[2 * y2 - y1]) / (h * h);
10398-        h /= 2;
10399-        i++;
10400-      }
10401-      a = g.length;
10402-      m = 1;
10403-      while (a != 1) {
10404-        for (j = 0; j < a - 1; j++)
10405-          h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);
10406-        a = h1.length;
10407-        g = h1;
10408-        h1 = [];
10409-        m++;
10410-      }
10411-      return g;
10412-    },
10413-
10414-    simpson: function simpson(f, a, b, n) {
10415-      var h = (b - a) / n;
10416-      var I = f(a);
10417-      var x = [];
10418-      var j = a;
10419-      var k = 0;
10420-      var i = 1;
10421-      var m;
10422-      for (; j <= b; j = j + h, k++)
10423-        x[k] = j;
10424-      m = x.length;
10425-      for (; i < m - 1; i++) {
10426-        I += ((i % 2 !== 0) ? 4 : 2) * f(x[i]);
10427-      }
10428-      return (h / 3) * (I + f(b));
10429-    },
10430-
10431-    hermite: function hermite(X, F, dF, value) {
10432-      var n = X.length;
10433-      var p = 0;
10434-      var i = 0;
10435-      var l = [];
10436-      var dl = [];
10437-      var A = [];
10438-      var B = [];
10439-      var j;
10440-      for (; i < n; i++) {
10441-        l[i] = 1;
10442-        for (j = 0; j < n; j++) {
10443-          if (i != j) l[i] *= (value - X[j]) / (X[i] - X[j]);
10444-        }
10445-        dl[i] = 0;
10446-        for (j = 0; j < n; j++) {
10447-          if (i != j) dl[i] += 1 / (X [i] - X[j]);
10448-        }
10449-        A[i] = (1 - 2 * (value - X[i]) * dl[i]) * (l[i] * l[i]);
10450-        B[i] = (value - X[i]) * (l[i] * l[i]);
10451-        p += (A[i] * F[i] + B[i] * dF[i]);
10452-      }
10453-      return p;
10454-    },
10455-
10456-    lagrange: function lagrange(X, F, value) {
10457-      var p = 0;
10458-      var i = 0;
10459-      var j, l;
10460-      var n = X.length;
10461-      for (; i < n; i++) {
10462-        l = F[i];
10463-        for (j = 0; j < n; j++) {
10464-          // calculating the lagrange polynomial L_i
10465-          if (i != j) l *= (value - X[j]) / (X[i] - X[j]);
10466-        }
10467-        // adding the lagrange polynomials found above
10468-        p += l;
10469-      }
10470-      return p;
10471-    },
10472-
10473-    cubic_spline: function cubic_spline(X, F, value) {
10474-      var n = X.length;
10475-      var i = 0, j;
10476-      var A = [];
10477-      var B = [];
10478-      var alpha = [];
10479-      var c = [];
10480-      var h = [];
10481-      var b = [];
10482-      var d = [];
10483-      for (; i < n - 1; i++)
10484-        h[i] = X[i + 1] - X[i];
10485-      alpha[0] = 0;
10486-      for (i = 1; i < n - 1; i++) {
10487-        alpha[i] = (3 / h[i]) * (F[i + 1] - F[i]) -
10488-          (3 / h[i-1]) * (F[i] - F[i-1]);
10489-      }
10490-      for (i = 1; i < n - 1; i++) {
10491-        A[i] = [];
10492-        B[i] = [];
10493-        A[i][i-1] = h[i-1];
10494-        A[i][i] = 2 * (h[i - 1] + h[i]);
10495-        A[i][i+1] = h[i];
10496-        B[i][0] = alpha[i];
10497-      }
10498-      c = jStat.multiply(jStat.inv(A), B);
10499-      for (j = 0; j < n - 1; j++) {
10500-        b[j] = (F[j + 1] - F[j]) / h[j] - h[j] * (c[j + 1][0] + 2 * c[j][0]) / 3;
10501-        d[j] = (c[j + 1][0] - c[j][0]) / (3 * h[j]);
10502-      }
10503-      for (j = 0; j < n; j++) {
10504-        if (X[j] > value) break;
10505-      }
10506-      j -= 1;
10507-      return F[j] + (value - X[j]) * b[j] + jStat.sq(value-X[j]) *
10508-        c[j] + (value - X[j]) * jStat.sq(value - X[j]) * d[j];
10509-    },
10510-
10511-    gauss_quadrature: function gauss_quadrature() {
10512-      throw new Error('gauss_quadrature not yet implemented');
10513-    },
10514-
10515-    PCA: function PCA(X) {
10516-      var m = X.length;
10517-      var n = X[0].length;
10518-      var flag = false;
10519-      var i = 0;
10520-      var j, temp1;
10521-      var u = [];
10522-      var D = [];
10523-      var result = [];
10524-      var temp2 = [];
10525-      var Y = [];
10526-      var Bt = [];
10527-      var B = [];
10528-      var C = [];
10529-      var V = [];
10530-      var Vt = [];
10531-      for (i = 0; i < m; i++) {
10532-        u[i] = jStat.sum(X[i]) / n;
10533-      }
10534-      for (i = 0; i < n; i++) {
10535-        B[i] = [];
10536-        for(j = 0; j < m; j++) {
10537-          B[i][j] = X[j][i] - u[j];
10538-        }
10539-      }
10540-      B = jStat.transpose(B);
10541-      for (i = 0; i < m; i++) {
10542-        C[i] = [];
10543-        for (j = 0; j < m; j++) {
10544-          C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1);
10545-        }
10546-      }
10547-      result = jStat.jacobi(C);
10548-      V = result[0];
10549-      D = result[1];
10550-      Vt = jStat.transpose(V);
10551-      for (i = 0; i < D.length; i++) {
10552-        for (j = i; j < D.length; j++) {
10553-          if(D[i] < D[j])  {
10554-            temp1 = D[i];
10555-            D[i] = D[j];
10556-            D[j] = temp1;
10557-            temp2 = Vt[i];
10558-            Vt[i] = Vt[j];
10559-            Vt[j] = temp2;
10560-          }
10561-        }
10562-      }
10563-      Bt = jStat.transpose(B);
10564-      for (i = 0; i < m; i++) {
10565-        Y[i] = [];
10566-        for (j = 0; j < Bt.length; j++) {
10567-          Y[i][j] = jStat.dot([Vt[i]], [Bt[j]]);
10568-        }
10569-      }
10570-      return [X, D, Vt, Y];
10571-    }
10572-  });
10573-
10574-// extend jStat.fn with methods that require one argument
10575-  (function(funcs) {
10576-    for (var i = 0; i < funcs.length; i++) (function(passfunc) {
10577-      jStat.fn[passfunc] = function(arg, func) {
10578-        var tmpthis = this;
10579-        // check for callback
10580-        if (func) {
10581-          setTimeout(function() {
10582-            func.call(tmpthis, jStat.fn[passfunc].call(tmpthis, arg));
10583-          }, 15);
10584-          return this;
10585-        }
10586-        return jStat(jStat[passfunc](this, arg));
10587-      };
10588-    }(funcs[i]));
10589-  }('add divide multiply subtract dot pow abs norm angle'.split(' ')));
10590-
10591-}(this.jStat, Math));
10592-(function(jStat, Math) {
10593-
10594-  var slice = [].slice;
10595-  var isNumber = jStat.utils.isNumber;
10596-
10597-// flag==true denotes use of sample standard deviation
10598-// Z Statistics
10599-  jStat.extend({
10600-    // 2 different parameter lists:
10601-    // (value, mean, sd)
10602-    // (value, array, flag)
10603-    zscore: function zscore() {
10604-      var args = slice.call(arguments);
10605-      if (isNumber(args[1])) {
10606-        return (args[0] - args[1]) / args[2];
10607-      }
10608-      return (args[0] - jStat.mean(args[1])) / jStat.stdev(args[1], args[2]);
10609-    },
10610-
10611-    // 3 different paramter lists:
10612-    // (value, mean, sd, sides)
10613-    // (zscore, sides)
10614-    // (value, array, sides, flag)
10615-    ztest: function ztest() {
10616-      var args = slice.call(arguments);
10617-      if (args.length === 4) {
10618-        if(isNumber(args[1])) {
10619-          var z = jStat.zscore(args[0],args[1],args[2])
10620-          return (args[3] === 1) ?
10621-            (jStat.normal.cdf(-Math.abs(z),0,1)) :
10622-            (jStat.normal.cdf(-Math.abs(z),0,1)* 2);
10623-        }
10624-        var z = args[0]
10625-        return (args[2] === 1) ?
10626-          (jStat.normal.cdf(-Math.abs(z),0,1)) :
10627-          (jStat.normal.cdf(-Math.abs(z),0,1)*2);
10628-      }
10629-      var z = jStat.zscore(args[0],args[1],args[3])
10630-      return (args[1] === 1) ?
10631-        (jStat.normal.cdf(-Math.abs(z), 0, 1)) :
10632-        (jStat.normal.cdf(-Math.abs(z), 0, 1)*2);
10633-    }
10634-  });
10635-
10636-  jStat.extend(jStat.fn, {
10637-    zscore: function zscore(value, flag) {
10638-      return (value - this.mean()) / this.stdev(flag);
10639-    },
10640-
10641-    ztest: function ztest(value, sides, flag) {
10642-      var zscore = Math.abs(this.zscore(value, flag));
10643-      return (sides === 1) ?
10644-        (jStat.normal.cdf(-zscore, 0, 1)) :
10645-        (jStat.normal.cdf(-zscore, 0, 1) * 2);
10646-    }
10647-  });
10648-
10649-// T Statistics
10650-  jStat.extend({
10651-    // 2 parameter lists
10652-    // (value, mean, sd, n)
10653-    // (value, array)
10654-    tscore: function tscore() {
10655-      var args = slice.call(arguments);
10656-      return (args.length === 4) ?
10657-        ((args[0] - args[1]) / (args[2] / Math.sqrt(args[3]))) :
10658-        ((args[0] - jStat.mean(args[1])) /
10659-        (jStat.stdev(args[1], true) / Math.sqrt(args[1].length)));
10660-    },
10661-
10662-    // 3 different paramter lists:
10663-    // (value, mean, sd, n, sides)
10664-    // (tscore, n, sides)
10665-    // (value, array, sides)
10666-    ttest: function ttest() {
10667-      var args = slice.call(arguments);
10668-      var tscore;
10669-      if (args.length === 5) {
10670-        tscore = Math.abs(jStat.tscore(args[0], args[1], args[2], args[3]));
10671-        return (args[4] === 1) ?
10672-          (jStat.studentt.cdf(-tscore, args[3]-1)) :
10673-          (jStat.studentt.cdf(-tscore, args[3]-1)*2);
10674-      }
10675-      if (isNumber(args[1])) {
10676-        tscore = Math.abs(args[0])
10677-        return (args[2] == 1) ?
10678-          (jStat.studentt.cdf(-tscore, args[1]-1)) :
10679-          (jStat.studentt.cdf(-tscore, args[1]-1) * 2);
10680-      }
10681-      tscore = Math.abs(jStat.tscore(args[0], args[1]))
10682-      return (args[2] == 1) ?
10683-        (jStat.studentt.cdf(-tscore, args[1].length-1)) :
10684-        (jStat.studentt.cdf(-tscore, args[1].length-1) * 2);
10685-    }
10686-  });
10687-
10688-  jStat.extend(jStat.fn, {
10689-    tscore: function tscore(value) {
10690-      return (value - this.mean()) / (this.stdev(true) / Math.sqrt(this.cols()));
10691-    },
10692-
10693-    ttest: function ttest(value, sides) {
10694-      return (sides === 1) ?
10695-        (1 - jStat.studentt.cdf(Math.abs(this.tscore(value)), this.cols()-1)) :
10696-        (jStat.studentt.cdf(-Math.abs(this.tscore(value)), this.cols()-1)*2);
10697-    }
10698-  });
10699-
10700-// F Statistics
10701-  jStat.extend({
10702-    // Paramter list is as follows:
10703-    // (array1, array2, array3, ...)
10704-    // or it is an array of arrays
10705-    // array of arrays conversion
10706-    anovafscore: function anovafscore() {
10707-      var args = slice.call(arguments),
10708-        expVar, sample, sampMean, sampSampMean, tmpargs, unexpVar, i, j;
10709-      if (args.length === 1) {
10710-        tmpargs = new Array(args[0].length);
10711-        for (i = 0; i < args[0].length; i++) {
10712-          tmpargs[i] = args[0][i];
10713-        }
10714-        args = tmpargs;
10715-      }
10716-      // 2 sample case
10717-      if (args.length === 2) {
10718-        return jStat.variance(args[0]) / jStat.variance(args[1]);
10719-      }
10720-      // Builds sample array
10721-      sample = new Array();
10722-      for (i = 0; i < args.length; i++) {
10723-        sample = sample.concat(args[i]);
10724-      }
10725-      sampMean = jStat.mean(sample);
10726-      // Computes the explained variance
10727-      expVar = 0;
10728-      for (i = 0; i < args.length; i++) {
10729-        expVar = expVar + args[i].length * Math.pow(jStat.mean(args[i]) - sampMean, 2);
10730-      }
10731-      expVar /= (args.length - 1);
10732-      // Computes unexplained variance
10733-      unexpVar = 0;
10734-      for (i = 0; i < args.length; i++) {
10735-        sampSampMean = jStat.mean(args[i]);
10736-        for (j = 0; j < args[i].length; j++) {
10737-          unexpVar += Math.pow(args[i][j] - sampSampMean, 2);
10738-        }
10739-      }
10740-      unexpVar /= (sample.length - args.length);
10741-      return expVar / unexpVar;
10742-    },
10743-
10744-    // 2 different paramter setups
10745-    // (array1, array2, array3, ...)
10746-    // (anovafscore, df1, df2)
10747-    anovaftest: function anovaftest() {
10748-      var args = slice.call(arguments),
10749-        df1, df2, n, i;
10750-      if (isNumber(args[0])) {
10751-        return 1 - jStat.centralF.cdf(args[0], args[1], args[2]);
10752-      }
10753-      anovafscore = jStat.anovafscore(args);
10754-      df1 = args.length - 1;
10755-      n = 0;
10756-      for (i = 0; i < args.length; i++) {
10757-        n = n + args[i].length;
10758-      }
10759-      df2 = n - df1 - 1;
10760-      return 1 - jStat.centralF.cdf(anovafscore, df1, df2);
10761-    },
10762-
10763-    ftest: function ftest(fscore, df1, df2) {
10764-      return 1 - jStat.centralF.cdf(fscore, df1, df2);
10765-    }
10766-  });
10767-
10768-  jStat.extend(jStat.fn, {
10769-    anovafscore: function anovafscore() {
10770-      return jStat.anovafscore(this.toArray());
10771-    },
10772-
10773-    anovaftes: function anovaftes() {
10774-      var n = 0;
10775-      var i;
10776-      for (i = 0; i < this.length; i++) {
10777-        n = n + this[i].length;
10778-      }
10779-      return jStat.ftest(this.anovafscore(), this.length - 1, n - this.length);
10780-    }
10781-  });
10782-
10783-// Error Bounds
10784-  jStat.extend({
10785-    // 2 different parameter setups
10786-    // (value, alpha, sd, n)
10787-    // (value, alpha, array)
10788-    normalci: function normalci() {
10789-      var args = slice.call(arguments),
10790-        ans = new Array(2),
10791-        change;
10792-      if (args.length === 4) {
10793-        change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *
10794-          args[2] / Math.sqrt(args[3]));
10795-      } else {
10796-        change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *
10797-          jStat.stdev(args[2]) / Math.sqrt(args[2].length));
10798-      }
10799-      ans[0] = args[0] - change;
10800-      ans[1] = args[0] + change;
10801-      return ans;
10802-    },
10803-
10804-    // 2 different parameter setups
10805-    // (value, alpha, sd, n)
10806-    // (value, alpha, array)
10807-    tci: function tci() {
10808-      var args = slice.call(arguments),
10809-        ans = new Array(2),
10810-        change;
10811-      if (args.length === 4) {
10812-        change = Math.abs(jStat.studentt.inv(args[1] / 2, args[3] - 1) *
10813-          args[2] / Math.sqrt(args[3]));
10814-      } else {
10815-        change = Math.abs(jStat.studentt.inv(args[1] / 2, args[2].length - 1) *
10816-          jStat.stdev(args[2], true) / Math.sqrt(args[2].length));
10817-      }
10818-      ans[0] = args[0] - change;
10819-      ans[1] = args[0] + change;
10820-      return ans;
10821-    },
10822-
10823-    significant: function significant(pvalue, alpha) {
10824-      return pvalue < alpha;
10825-    }
10826-  });
10827-
10828-  jStat.extend(jStat.fn, {
10829-    normalci: function normalci(value, alpha) {
10830-      return jStat.normalci(value, alpha, this.toArray());
10831-    },
10832-
10833-    tci: function tci(value, alpha) {
10834-      return jStat.tci(value, alpha, this.toArray());
10835-    }
10836-  });
10837-
10838-}(this.jStat, Math));
10839diff --git a/lib/lodash/lodash.js b/lib/lodash/lodash.js
10840deleted file mode 100644
10841index 1121a05..0000000
10842--- a/lib/lodash/lodash.js
10843+++ /dev/null
10844@@ -1,6789 +0,0 @@
10845-/**
10846- * @license
10847- * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
10848- * Build: `lodash modern -o ./dist/lodash.js`
10849- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
10850- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
10851- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
10852- * Available under MIT license <http://lodash.com/license>
10853- */
10854-;(function() {
10855-
10856-  /** Used as a safe reference for `undefined` in pre ES5 environments */
10857-  var undefined;
10858-
10859-  /** Used to pool arrays and objects used internally */
10860-  var arrayPool = [],
10861-    objectPool = [];
10862-
10863-  /** Used to generate unique IDs */
10864-  var idCounter = 0;
10865-
10866-  /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
10867-  var keyPrefix = +new Date + '';
10868-
10869-  /** Used as the size when optimizations are enabled for large arrays */
10870-  var largeArraySize = 75;
10871-
10872-  /** Used as the max size of the `arrayPool` and `objectPool` */
10873-  var maxPoolSize = 40;
10874-
10875-  /** Used to detect and test whitespace */
10876-  var whitespace = (
10877-    // whitespace
10878-    ' \t\x0B\f\xA0\ufeff' +
10879-
10880-    // line terminators
10881-    '\n\r\u2028\u2029' +
10882-
10883-    // unicode category "Zs" space separators
10884-    '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
10885-  );
10886-
10887-  /** Used to match empty string literals in compiled template source */
10888-  var reEmptyStringLeading = /\b__p \+= '';/g,
10889-    reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
10890-    reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
10891-
10892-  /**
10893-   * Used to match ES6 template delimiters
10894-   * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
10895-   */
10896-  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
10897-
10898-  /** Used to match regexp flags from their coerced string values */
10899-  var reFlags = /\w*$/;
10900-
10901-  /** Used to detected named functions */
10902-  var reFuncName = /^\s*function[ \n\r\t]+\w/;
10903-
10904-  /** Used to match "interpolate" template delimiters */
10905-  var reInterpolate = /<%=([\s\S]+?)%>/g;
10906-
10907-  /** Used to match leading whitespace and zeros to be removed */
10908-  var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
10909-
10910-  /** Used to ensure capturing order of template delimiters */
10911-  var reNoMatch = /($^)/;
10912-
10913-  /** Used to detect functions containing a `this` reference */
10914-  var reThis = /\bthis\b/;
10915-
10916-  /** Used to match unescaped characters in compiled string literals */
10917-  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
10918-
10919-  /** Used to assign default `context` object properties */
10920-  var contextProps = [
10921-    'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
10922-    'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
10923-    'parseInt', 'setTimeout'
10924-  ];
10925-
10926-  /** Used to make template sourceURLs easier to identify */
10927-  var templateCounter = 0;
10928-
10929-  /** `Object#toString` result shortcuts */
10930-  var argsClass = '[object Arguments]',
10931-    arrayClass = '[object Array]',
10932-    boolClass = '[object Boolean]',
10933-    dateClass = '[object Date]',
10934-    funcClass = '[object Function]',
10935-    numberClass = '[object Number]',
10936-    objectClass = '[object Object]',
10937-    regexpClass = '[object RegExp]',
10938-    stringClass = '[object String]';
10939-
10940-  /** Used to identify object classifications that `_.clone` supports */
10941-  var cloneableClasses = {};
10942-  cloneableClasses[funcClass] = false;
10943-  cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
10944-    cloneableClasses[boolClass] = cloneableClasses[dateClass] =
10945-      cloneableClasses[numberClass] = cloneableClasses[objectClass] =
10946-        cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
10947-
10948-  /** Used as an internal `_.debounce` options object */
10949-  var debounceOptions = {
10950-    'leading': false,
10951-    'maxWait': 0,
10952-    'trailing': false
10953-  };
10954-
10955-  /** Used as the property descriptor for `__bindData__` */
10956-  var descriptor = {
10957-    'configurable': false,
10958-    'enumerable': false,
10959-    'value': null,
10960-    'writable': false
10961-  };
10962-
10963-  /** Used to determine if values are of the language type Object */
10964-  var objectTypes = {
10965-    'boolean': false,
10966-    'function': true,
10967-    'object': true,
10968-    'number': false,
10969-    'string': false,
10970-    'undefined': false
10971-  };
10972-
10973-  /** Used to escape characters for inclusion in compiled string literals */
10974-  var stringEscapes = {
10975-    '\\': '\\',
10976-    "'": "'",
10977-    '\n': 'n',
10978-    '\r': 'r',
10979-    '\t': 't',
10980-    '\u2028': 'u2028',
10981-    '\u2029': 'u2029'
10982-  };
10983-
10984-  /** Used as a reference to the global object */
10985-  var root = (objectTypes[typeof window] && window) || this;
10986-
10987-  /** Detect free variable `exports` */
10988-  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
10989-
10990-  /** Detect free variable `module` */
10991-  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
10992-
10993-  /** Detect the popular CommonJS extension `module.exports` */
10994-  var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
10995-
10996-  /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
10997-  var freeGlobal = objectTypes[typeof global] && global;
10998-  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
10999-    root = freeGlobal;
11000-  }
11001-
11002-  /*--------------------------------------------------------------------------*/
11003-
11004-  /**
11005-   * The base implementation of `_.indexOf` without support for binary searches
11006-   * or `fromIndex` constraints.
11007-   *
11008-   * @private
11009-   * @param {Array} array The array to search.
11010-   * @param {*} value The value to search for.
11011-   * @param {number} [fromIndex=0] The index to search from.
11012-   * @returns {number} Returns the index of the matched value or `-1`.
11013-   */
11014-  function baseIndexOf(array, value, fromIndex) {
11015-    var index = (fromIndex || 0) - 1,
11016-      length = array ? array.length : 0;
11017-
11018-    while (++index < length) {
11019-      if (array[index] === value) {
11020-        return index;
11021-      }
11022-    }
11023-    return -1;
11024-  }
11025-
11026-  /**
11027-   * An implementation of `_.contains` for cache objects that mimics the return
11028-   * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
11029-   *
11030-   * @private
11031-   * @param {Object} cache The cache object to inspect.
11032-   * @param {*} value The value to search for.
11033-   * @returns {number} Returns `0` if `value` is found, else `-1`.
11034-   */
11035-  function cacheIndexOf(cache, value) {
11036-    var type = typeof value;
11037-    cache = cache.cache;
11038-
11039-    if (type == 'boolean' || value == null) {
11040-      return cache[value] ? 0 : -1;
11041-    }
11042-    if (type != 'number' && type != 'string') {
11043-      type = 'object';
11044-    }
11045-    var key = type == 'number' ? value : keyPrefix + value;
11046-    cache = (cache = cache[type]) && cache[key];
11047-
11048-    return type == 'object'
11049-      ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
11050-      : (cache ? 0 : -1);
11051-  }
11052-
11053-  /**
11054-   * Adds a given value to the corresponding cache object.
11055-   *
11056-   * @private
11057-   * @param {*} value The value to add to the cache.
11058-   */
11059-  function cachePush(value) {
11060-    var cache = this.cache,
11061-      type = typeof value;
11062-
11063-    if (type == 'boolean' || value == null) {
11064-      cache[value] = true;
11065-    } else {
11066-      if (type != 'number' && type != 'string') {
11067-        type = 'object';
11068-      }
11069-      var key = type == 'number' ? value : keyPrefix + value,
11070-        typeCache = cache[type] || (cache[type] = {});
11071-
11072-      if (type == 'object') {
11073-        (typeCache[key] || (typeCache[key] = [])).push(value);
11074-      } else {
11075-        typeCache[key] = true;
11076-      }
11077-    }
11078-  }
11079-
11080-  /**
11081-   * Used by `_.max` and `_.min` as the default callback when a given
11082-   * collection is a string value.
11083-   *
11084-   * @private
11085-   * @param {string} value The character to inspect.
11086-   * @returns {number} Returns the code unit of given character.
11087-   */
11088-  function charAtCallback(value) {
11089-    return value.charCodeAt(0);
11090-  }
11091-
11092-  /**
11093-   * Used by `sortBy` to compare transformed `collection` elements, stable sorting
11094-   * them in ascending order.
11095-   *
11096-   * @private
11097-   * @param {Object} a The object to compare to `b`.
11098-   * @param {Object} b The object to compare to `a`.
11099-   * @returns {number} Returns the sort order indicator of `1` or `-1`.
11100-   */
11101-  function compareAscending(a, b) {
11102-    var ac = a.criteria,
11103-      bc = b.criteria,
11104-      index = -1,
11105-      length = ac.length;
11106-
11107-    while (++index < length) {
11108-      var value = ac[index],
11109-        other = bc[index];
11110-
11111-      if (value !== other) {
11112-        if (value > other || typeof value == 'undefined') {
11113-          return 1;
11114-        }
11115-        if (value < other || typeof other == 'undefined') {
11116-          return -1;
11117-        }
11118-      }
11119-    }
11120-    // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
11121-    // that causes it, under certain circumstances, to return the same value for
11122-    // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
11123-    //
11124-    // This also ensures a stable sort in V8 and other engines.
11125-    // See http://code.google.com/p/v8/issues/detail?id=90
11126-    return a.index - b.index;
11127-  }
11128-
11129-  /**
11130-   * Creates a cache object to optimize linear searches of large arrays.
11131-   *
11132-   * @private
11133-   * @param {Array} [array=[]] The array to search.
11134-   * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
11135-   */
11136-  function createCache(array) {
11137-    var index = -1,
11138-      length = array.length,
11139-      first = array[0],
11140-      mid = array[(length / 2) | 0],
11141-      last = array[length - 1];
11142-
11143-    if (first && typeof first == 'object' &&
11144-      mid && typeof mid == 'object' && last && typeof last == 'object') {
11145-      return false;
11146-    }
11147-    var cache = getObject();
11148-    cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
11149-
11150-    var result = getObject();
11151-    result.array = array;
11152-    result.cache = cache;
11153-    result.push = cachePush;
11154-
11155-    while (++index < length) {
11156-      result.push(array[index]);
11157-    }
11158-    return result;
11159-  }
11160-
11161-  /**
11162-   * Used by `template` to escape characters for inclusion in compiled
11163-   * string literals.
11164-   *
11165-   * @private
11166-   * @param {string} match The matched character to escape.
11167-   * @returns {string} Returns the escaped character.
11168-   */
11169-  function escapeStringChar(match) {
11170-    return '\\' + stringEscapes[match];
11171-  }
11172-
11173-  /**
11174-   * Gets an array from the array pool or creates a new one if the pool is empty.
11175-   *
11176-   * @private
11177-   * @returns {Array} The array from the pool.
11178-   */
11179-  function getArray() {
11180-    return arrayPool.pop() || [];
11181-  }
11182-
11183-  /**
11184-   * Gets an object from the object pool or creates a new one if the pool is empty.
11185-   *
11186-   * @private
11187-   * @returns {Object} The object from the pool.
11188-   */
11189-  function getObject() {
11190-    return objectPool.pop() || {
11191-        'array': null,
11192-        'cache': null,
11193-        'criteria': null,
11194-        'false': false,
11195-        'index': 0,
11196-        'null': false,
11197-        'number': null,
11198-        'object': null,
11199-        'push': null,
11200-        'string': null,
11201-        'true': false,
11202-        'undefined': false,
11203-        'value': null
11204-      };
11205-  }
11206-
11207-  /**
11208-   * Releases the given array back to the array pool.
11209-   *
11210-   * @private
11211-   * @param {Array} [array] The array to release.
11212-   */
11213-  function releaseArray(array) {
11214-    array.length = 0;
11215-    if (arrayPool.length < maxPoolSize) {
11216-      arrayPool.push(array);
11217-    }
11218-  }
11219-
11220-  /**
11221-   * Releases the given object back to the object pool.
11222-   *
11223-   * @private
11224-   * @param {Object} [object] The object to release.
11225-   */
11226-  function releaseObject(object) {
11227-    var cache = object.cache;
11228-    if (cache) {
11229-      releaseObject(cache);
11230-    }
11231-    object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
11232-    if (objectPool.length < maxPoolSize) {
11233-      objectPool.push(object);
11234-    }
11235-  }
11236-
11237-  /**
11238-   * Slices the `collection` from the `start` index up to, but not including,
11239-   * the `end` index.
11240-   *
11241-   * Note: This function is used instead of `Array#slice` to support node lists
11242-   * in IE < 9 and to ensure dense arrays are returned.
11243-   *
11244-   * @private
11245-   * @param {Array|Object|string} collection The collection to slice.
11246-   * @param {number} start The start index.
11247-   * @param {number} end The end index.
11248-   * @returns {Array} Returns the new array.
11249-   */
11250-  function slice(array, start, end) {
11251-    start || (start = 0);
11252-    if (typeof end == 'undefined') {
11253-      end = array ? array.length : 0;
11254-    }
11255-    var index = -1,
11256-      length = end - start || 0,
11257-      result = Array(length < 0 ? 0 : length);
11258-
11259-    while (++index < length) {
11260-      result[index] = array[start + index];
11261-    }
11262-    return result;
11263-  }
11264-
11265-  /*--------------------------------------------------------------------------*/
11266-
11267-  /**
11268-   * Create a new `lodash` function using the given context object.
11269-   *
11270-   * @static
11271-   * @memberOf _
11272-   * @category Utilities
11273-   * @param {Object} [context=root] The context object.
11274-   * @returns {Function} Returns the `lodash` function.
11275-   */
11276-  function runInContext(context) {
11277-    // Avoid issues with some ES3 environments that attempt to use values, named
11278-    // after built-in constructors like `Object`, for the creation of literals.
11279-    // ES5 clears this up by stating that literals must use built-in constructors.
11280-    // See http://es5.github.io/#x11.1.5.
11281-    context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
11282-
11283-    /** Native constructor references */
11284-    var Array = context.Array,
11285-      Boolean = context.Boolean,
11286-      Date = context.Date,
11287-      Function = context.Function,
11288-      Math = context.Math,
11289-      Number = context.Number,
11290-      Object = context.Object,
11291-      RegExp = context.RegExp,
11292-      String = context.String,
11293-      TypeError = context.TypeError;
11294-
11295-    /**
11296-     * Used for `Array` method references.
11297-     *
11298-     * Normally `Array.prototype` would suffice, however, using an array literal
11299-     * avoids issues in Narwhal.
11300-     */
11301-    var arrayRef = [];
11302-
11303-    /** Used for native method references */
11304-    var objectProto = Object.prototype;
11305-
11306-    /** Used to restore the original `_` reference in `noConflict` */
11307-    var oldDash = context._;
11308-
11309-    /** Used to resolve the internal [[Class]] of values */
11310-    var toString = objectProto.toString;
11311-
11312-    /** Used to detect if a method is native */
11313-    var reNative = RegExp('^' +
11314-      String(toString)
11315-        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
11316-        .replace(/toString| for [^\]]+/g, '.*?') + '$'
11317-    );
11318-
11319-    /** Native method shortcuts */
11320-    var ceil = Math.ceil,
11321-      clearTimeout = context.clearTimeout,
11322-      floor = Math.floor,
11323-      fnToString = Function.prototype.toString,
11324-      getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
11325-      hasOwnProperty = objectProto.hasOwnProperty,
11326-      push = arrayRef.push,
11327-      setTimeout = context.setTimeout,
11328-      splice = arrayRef.splice,
11329-      unshift = arrayRef.unshift;
11330-
11331-    /** Used to set meta data on functions */
11332-    var defineProperty = (function() {
11333-      // IE 8 only accepts DOM elements
11334-      try {
11335-        var o = {},
11336-          func = isNative(func = Object.defineProperty) && func,
11337-          result = func(o, o, o) && func;
11338-      } catch(e) { }
11339-      return result;
11340-    }());
11341-
11342-    /* Native method shortcuts for methods with the same name as other `lodash` methods */
11343-    var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
11344-      nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
11345-      nativeIsFinite = context.isFinite,
11346-      nativeIsNaN = context.isNaN,
11347-      nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
11348-      nativeMax = Math.max,
11349-      nativeMin = Math.min,
11350-      nativeParseInt = context.parseInt,
11351-      nativeRandom = Math.random;
11352-
11353-    /** Used to lookup a built-in constructor by [[Class]] */
11354-    var ctorByClass = {};
11355-    ctorByClass[arrayClass] = Array;
11356-    ctorByClass[boolClass] = Boolean;
11357-    ctorByClass[dateClass] = Date;
11358-    ctorByClass[funcClass] = Function;
11359-    ctorByClass[objectClass] = Object;
11360-    ctorByClass[numberClass] = Number;
11361-    ctorByClass[regexpClass] = RegExp;
11362-    ctorByClass[stringClass] = String;
11363-
11364-    /*--------------------------------------------------------------------------*/
11365-
11366-    /**
11367-     * Creates a `lodash` object which wraps the given value to enable intuitive
11368-     * method chaining.
11369-     *
11370-     * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
11371-     * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
11372-     * and `unshift`
11373-     *
11374-     * Chaining is supported in custom builds as long as the `value` method is
11375-     * implicitly or explicitly included in the build.
11376-     *
11377-     * The chainable wrapper functions are:
11378-     * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
11379-     * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
11380-     * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
11381-     * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
11382-     * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
11383-     * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
11384-     * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
11385-     * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
11386-     * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
11387-     * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
11388-     * and `zip`
11389-     *
11390-     * The non-chainable wrapper functions are:
11391-     * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
11392-     * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
11393-     * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
11394-     * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
11395-     * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
11396-     * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
11397-     * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
11398-     * `template`, `unescape`, `uniqueId`, and `value`
11399-     *
11400-     * The wrapper functions `first` and `last` return wrapped values when `n` is
11401-     * provided, otherwise they return unwrapped values.
11402-     *
11403-     * Explicit chaining can be enabled by using the `_.chain` method.
11404-     *
11405-     * @name _
11406-     * @constructor
11407-     * @category Chaining
11408-     * @param {*} value The value to wrap in a `lodash` instance.
11409-     * @returns {Object} Returns a `lodash` instance.
11410-     * @example
11411-     *
11412-     * var wrapped = _([1, 2, 3]);
11413-     *
11414-     * // returns an unwrapped value
11415-     * wrapped.reduce(function(sum, num) {
11416-     *   return sum + num;
11417-     * });
11418-     * // => 6
11419-     *
11420-     * // returns a wrapped value
11421-     * var squares = wrapped.map(function(num) {
11422-     *   return num * num;
11423-     * });
11424-     *
11425-     * _.isArray(squares);
11426-     * // => false
11427-     *
11428-     * _.isArray(squares.value());
11429-     * // => true
11430-     */
11431-    function lodash(value) {
11432-      // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
11433-      return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
11434-        ? value
11435-        : new lodashWrapper(value);
11436-    }
11437-
11438-    /**
11439-     * A fast path for creating `lodash` wrapper objects.
11440-     *
11441-     * @private
11442-     * @param {*} value The value to wrap in a `lodash` instance.
11443-     * @param {boolean} chainAll A flag to enable chaining for all methods
11444-     * @returns {Object} Returns a `lodash` instance.
11445-     */
11446-    function lodashWrapper(value, chainAll) {
11447-      this.__chain__ = !!chainAll;
11448-      this.__wrapped__ = value;
11449-    }
11450-    // ensure `new lodashWrapper` is an instance of `lodash`
11451-    lodashWrapper.prototype = lodash.prototype;
11452-
11453-    /**
11454-     * An object used to flag environments features.
11455-     *
11456-     * @static
11457-     * @memberOf _
11458-     * @type Object
11459-     */
11460-    var support = lodash.support = {};
11461-
11462-    /**
11463-     * Detect if functions can be decompiled by `Function#toString`
11464-     * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
11465-     *
11466-     * @memberOf _.support
11467-     * @type boolean
11468-     */
11469-    support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
11470-
11471-    /**
11472-     * Detect if `Function#name` is supported (all but IE).
11473-     *
11474-     * @memberOf _.support
11475-     * @type boolean
11476-     */
11477-    support.funcNames = typeof Function.name == 'string';
11478-
11479-    /**
11480-     * By default, the template delimiters used by Lo-Dash are similar to those in
11481-     * embedded Ruby (ERB). Change the following template settings to use alternative
11482-     * delimiters.
11483-     *
11484-     * @static
11485-     * @memberOf _
11486-     * @type Object
11487-     */
11488-    lodash.templateSettings = {
11489-
11490-      /**
11491-       * Used to detect `data` property values to be HTML-escaped.
11492-       *
11493-       * @memberOf _.templateSettings
11494-       * @type RegExp
11495-       */
11496-      'escape': /<%-([\s\S]+?)%>/g,
11497-
11498-      /**
11499-       * Used to detect code to be evaluated.
11500-       *
11501-       * @memberOf _.templateSettings
11502-       * @type RegExp
11503-       */
11504-      'evaluate': /<%([\s\S]+?)%>/g,
11505-
11506-      /**
11507-       * Used to detect `data` property values to inject.
11508-       *
11509-       * @memberOf _.templateSettings
11510-       * @type RegExp
11511-       */
11512-      'interpolate': reInterpolate,
11513-
11514-      /**
11515-       * Used to reference the data object in the template text.
11516-       *
11517-       * @memberOf _.templateSettings
11518-       * @type string
11519-       */
11520-      'variable': '',
11521-
11522-      /**
11523-       * Used to import variables into the compiled template.
11524-       *
11525-       * @memberOf _.templateSettings
11526-       * @type Object
11527-       */
11528-      'imports': {
11529-
11530-        /**
11531-         * A reference to the `lodash` function.
11532-         *
11533-         * @memberOf _.templateSettings.imports
11534-         * @type Function
11535-         */
11536-        '_': lodash
11537-      }
11538-    };
11539-
11540-    /*--------------------------------------------------------------------------*/
11541-
11542-    /**
11543-     * The base implementation of `_.bind` that creates the bound function and
11544-     * sets its meta data.
11545-     *
11546-     * @private
11547-     * @param {Array} bindData The bind data array.
11548-     * @returns {Function} Returns the new bound function.
11549-     */
11550-    function baseBind(bindData) {
11551-      var func = bindData[0],
11552-        partialArgs = bindData[2],
11553-        thisArg = bindData[4];
11554-
11555-      function bound() {
11556-        // `Function#bind` spec
11557-        // http://es5.github.io/#x15.3.4.5
11558-        if (partialArgs) {
11559-          // avoid `arguments` object deoptimizations by using `slice` instead
11560-          // of `Array.prototype.slice.call` and not assigning `arguments` to a
11561-          // variable as a ternary expression
11562-          var args = slice(partialArgs);
11563-          push.apply(args, arguments);
11564-        }
11565-        // mimic the constructor's `return` behavior
11566-        // http://es5.github.io/#x13.2.2
11567-        if (this instanceof bound) {
11568-          // ensure `new bound` is an instance of `func`
11569-          var thisBinding = baseCreate(func.prototype),
11570-            result = func.apply(thisBinding, args || arguments);
11571-          return isObject(result) ? result : thisBinding;
11572-        }
11573-        return func.apply(thisArg, args || arguments);
11574-      }
11575-      setBindData(bound, bindData);
11576-      return bound;
11577-    }
11578-
11579-    /**
11580-     * The base implementation of `_.clone` without argument juggling or support
11581-     * for `thisArg` binding.
11582-     *
11583-     * @private
11584-     * @param {*} value The value to clone.
11585-     * @param {boolean} [isDeep=false] Specify a deep clone.
11586-     * @param {Function} [callback] The function to customize cloning values.
11587-     * @param {Array} [stackA=[]] Tracks traversed source objects.
11588-     * @param {Array} [stackB=[]] Associates clones with source counterparts.
11589-     * @returns {*} Returns the cloned value.
11590-     */
11591-    function baseClone(value, isDeep, callback, stackA, stackB) {
11592-      if (callback) {
11593-        var result = callback(value);
11594-        if (typeof result != 'undefined') {
11595-          return result;
11596-        }
11597-      }
11598-      // inspect [[Class]]
11599-      var isObj = isObject(value);
11600-      if (isObj) {
11601-        var className = toString.call(value);
11602-        if (!cloneableClasses[className]) {
11603-          return value;
11604-        }
11605-        var ctor = ctorByClass[className];
11606-        switch (className) {
11607-          case boolClass:
11608-          case dateClass:
11609-            return new ctor(+value);
11610-
11611-          case numberClass:
11612-          case stringClass:
11613-            return new ctor(value);
11614-
11615-          case regexpClass:
11616-            result = ctor(value.source, reFlags.exec(value));
11617-            result.lastIndex = value.lastIndex;
11618-            return result;
11619-        }
11620-      } else {
11621-        return value;
11622-      }
11623-      var isArr = isArray(value);
11624-      if (isDeep) {
11625-        // check for circular references and return corresponding clone
11626-        var initedStack = !stackA;
11627-        stackA || (stackA = getArray());
11628-        stackB || (stackB = getArray());
11629-
11630-        var length = stackA.length;
11631-        while (length--) {
11632-          if (stackA[length] == value) {
11633-            return stackB[length];
11634-          }
11635-        }
11636-        result = isArr ? ctor(value.length) : {};
11637-      }
11638-      else {
11639-        result = isArr ? slice(value) : assign({}, value);
11640-      }
11641-      // add array properties assigned by `RegExp#exec`
11642-      if (isArr) {
11643-        if (hasOwnProperty.call(value, 'index')) {
11644-          result.index = value.index;
11645-        }
11646-        if (hasOwnProperty.call(value, 'input')) {
11647-          result.input = value.input;
11648-        }
11649-      }
11650-      // exit for shallow clone
11651-      if (!isDeep) {
11652-        return result;
11653-      }
11654-      // add the source value to the stack of traversed objects
11655-      // and associate it with its clone
11656-      stackA.push(value);
11657-      stackB.push(result);
11658-
11659-      // recursively populate clone (susceptible to call stack limits)
11660-      (isArr ? forEach : forOwn)(value, function(objValue, key) {
11661-        result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
11662-      });
11663-
11664-      if (initedStack) {
11665-        releaseArray(stackA);
11666-        releaseArray(stackB);
11667-      }
11668-      return result;
11669-    }
11670-
11671-    /**
11672-     * The base implementation of `_.create` without support for assigning
11673-     * properties to the created object.
11674-     *
11675-     * @private
11676-     * @param {Object} prototype The object to inherit from.
11677-     * @returns {Object} Returns the new object.
11678-     */
11679-    function baseCreate(prototype, properties) {
11680-      return isObject(prototype) ? nativeCreate(prototype) : {};
11681-    }
11682-    // fallback for browsers without `Object.create`
11683-    if (!nativeCreate) {
11684-      baseCreate = (function() {
11685-        function Object() {}
11686-        return function(prototype) {
11687-          if (isObject(prototype)) {
11688-            Object.prototype = prototype;
11689-            var result = new Object;
11690-            Object.prototype = null;
11691-          }
11692-          return result || context.Object();
11693-        };
11694-      }());
11695-    }
11696-
11697-    /**
11698-     * The base implementation of `_.createCallback` without support for creating
11699-     * "_.pluck" or "_.where" style callbacks.
11700-     *
11701-     * @private
11702-     * @param {*} [func=identity] The value to convert to a callback.
11703-     * @param {*} [thisArg] The `this` binding of the created callback.
11704-     * @param {number} [argCount] The number of arguments the callback accepts.
11705-     * @returns {Function} Returns a callback function.
11706-     */
11707-    function baseCreateCallback(func, thisArg, argCount) {
11708-      if (typeof func != 'function') {
11709-        return identity;
11710-      }
11711-      // exit early for no `thisArg` or already bound by `Function#bind`
11712-      if (typeof thisArg == 'undefined' || !('prototype' in func)) {
11713-        return func;
11714-      }
11715-      var bindData = func.__bindData__;
11716-      if (typeof bindData == 'undefined') {
11717-        if (support.funcNames) {
11718-          bindData = !func.name;
11719-        }
11720-        bindData = bindData || !support.funcDecomp;
11721-        if (!bindData) {
11722-          var source = fnToString.call(func);
11723-          if (!support.funcNames) {
11724-            bindData = !reFuncName.test(source);
11725-          }
11726-          if (!bindData) {
11727-            // checks if `func` references the `this` keyword and stores the result
11728-            bindData = reThis.test(source);
11729-            setBindData(func, bindData);
11730-          }
11731-        }
11732-      }
11733-      // exit early if there are no `this` references or `func` is bound
11734-      if (bindData === false || (bindData !== true && bindData[1] & 1)) {
11735-        return func;
11736-      }
11737-      switch (argCount) {
11738-        case 1: return function(value) {
11739-          return func.call(thisArg, value);
11740-        };
11741-        case 2: return function(a, b) {
11742-          return func.call(thisArg, a, b);
11743-        };
11744-        case 3: return function(value, index, collection) {
11745-          return func.call(thisArg, value, index, collection);
11746-        };
11747-        case 4: return function(accumulator, value, index, collection) {
11748-          return func.call(thisArg, accumulator, value, index, collection);
11749-        };
11750-      }
11751-      return bind(func, thisArg);
11752-    }
11753-
11754-    /**
11755-     * The base implementation of `createWrapper` that creates the wrapper and
11756-     * sets its meta data.
11757-     *
11758-     * @private
11759-     * @param {Array} bindData The bind data array.
11760-     * @returns {Function} Returns the new function.
11761-     */
11762-    function baseCreateWrapper(bindData) {
11763-      var func = bindData[0],
11764-        bitmask = bindData[1],
11765-        partialArgs = bindData[2],
11766-        partialRightArgs = bindData[3],
11767-        thisArg = bindData[4],
11768-        arity = bindData[5];
11769-
11770-      var isBind = bitmask & 1,
11771-        isBindKey = bitmask & 2,
11772-        isCurry = bitmask & 4,
11773-        isCurryBound = bitmask & 8,
11774-        key = func;
11775-
11776-      function bound() {
11777-        var thisBinding = isBind ? thisArg : this;
11778-        if (partialArgs) {
11779-          var args = slice(partialArgs);
11780-          push.apply(args, arguments);
11781-        }
11782-        if (partialRightArgs || isCurry) {
11783-          args || (args = slice(arguments));
11784-          if (partialRightArgs) {
11785-            push.apply(args, partialRightArgs);
11786-          }
11787-          if (isCurry && args.length < arity) {
11788-            bitmask |= 16 & ~32;
11789-            return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
11790-          }
11791-        }
11792-        args || (args = arguments);
11793-        if (isBindKey) {
11794-          func = thisBinding[key];
11795-        }
11796-        if (this instanceof bound) {
11797-          thisBinding = baseCreate(func.prototype);
11798-          var result = func.apply(thisBinding, args);
11799-          return isObject(result) ? result : thisBinding;
11800-        }
11801-        return func.apply(thisBinding, args);
11802-      }
11803-      setBindData(bound, bindData);
11804-      return bound;
11805-    }
11806-
11807-    /**
11808-     * The base implementation of `_.difference` that accepts a single array
11809-     * of values to exclude.
11810-     *
11811-     * @private
11812-     * @param {Array} array The array to process.
11813-     * @param {Array} [values] The array of values to exclude.
11814-     * @returns {Array} Returns a new array of filtered values.
11815-     */
11816-    function baseDifference(array, values) {
11817-      var index = -1,
11818-        indexOf = getIndexOf(),
11819-        length = array ? array.length : 0,
11820-        isLarge = length >= largeArraySize && indexOf === baseIndexOf,
11821-        result = [];
11822-
11823-      if (isLarge) {
11824-        var cache = createCache(values);
11825-        if (cache) {
11826-          indexOf = cacheIndexOf;
11827-          values = cache;
11828-        } else {
11829-          isLarge = false;
11830-        }
11831-      }
11832-      while (++index < length) {
11833-        var value = array[index];
11834-        if (indexOf(values, value) < 0) {
11835-          result.push(value);
11836-        }
11837-      }
11838-      if (isLarge) {
11839-        releaseObject(values);
11840-      }
11841-      return result;
11842-    }
11843-
11844-    /**
11845-     * The base implementation of `_.flatten` without support for callback
11846-     * shorthands or `thisArg` binding.
11847-     *
11848-     * @private
11849-     * @param {Array} array The array to flatten.
11850-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
11851-     * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
11852-     * @param {number} [fromIndex=0] The index to start from.
11853-     * @returns {Array} Returns a new flattened array.
11854-     */
11855-    function baseFlatten(array, isShallow, isStrict, fromIndex) {
11856-      var index = (fromIndex || 0) - 1,
11857-        length = array ? array.length : 0,
11858-        result = [];
11859-
11860-      while (++index < length) {
11861-        var value = array[index];
11862-
11863-        if (value && typeof value == 'object' && typeof value.length == 'number'
11864-          && (isArray(value) || isArguments(value))) {
11865-          // recursively flatten arrays (susceptible to call stack limits)
11866-          if (!isShallow) {
11867-            value = baseFlatten(value, isShallow, isStrict);
11868-          }
11869-          var valIndex = -1,
11870-            valLength = value.length,
11871-            resIndex = result.length;
11872-
11873-          result.length += valLength;
11874-          while (++valIndex < valLength) {
11875-            result[resIndex++] = value[valIndex];
11876-          }
11877-        } else if (!isStrict) {
11878-          result.push(value);
11879-        }
11880-      }
11881-      return result;
11882-    }
11883-
11884-    /**
11885-     * The base implementation of `_.isEqual`, without support for `thisArg` binding,
11886-     * that allows partial "_.where" style comparisons.
11887-     *
11888-     * @private
11889-     * @param {*} a The value to compare.
11890-     * @param {*} b The other value to compare.
11891-     * @param {Function} [callback] The function to customize comparing values.
11892-     * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
11893-     * @param {Array} [stackA=[]] Tracks traversed `a` objects.
11894-     * @param {Array} [stackB=[]] Tracks traversed `b` objects.
11895-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11896-     */
11897-    function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
11898-      // used to indicate that when comparing objects, `a` has at least the properties of `b`
11899-      if (callback) {
11900-        var result = callback(a, b);
11901-        if (typeof result != 'undefined') {
11902-          return !!result;
11903-        }
11904-      }
11905-      // exit early for identical values
11906-      if (a === b) {
11907-        // treat `+0` vs. `-0` as not equal
11908-        return a !== 0 || (1 / a == 1 / b);
11909-      }
11910-      var type = typeof a,
11911-        otherType = typeof b;
11912-
11913-      // exit early for unlike primitive values
11914-      if (a === a &&
11915-        !(a && objectTypes[type]) &&
11916-        !(b && objectTypes[otherType])) {
11917-        return false;
11918-      }
11919-      // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
11920-      // http://es5.github.io/#x15.3.4.4
11921-      if (a == null || b == null) {
11922-        return a === b;
11923-      }
11924-      // compare [[Class]] names
11925-      var className = toString.call(a),
11926-        otherClass = toString.call(b);
11927-
11928-      if (className == argsClass) {
11929-        className = objectClass;
11930-      }
11931-      if (otherClass == argsClass) {
11932-        otherClass = objectClass;
11933-      }
11934-      if (className != otherClass) {
11935-        return false;
11936-      }
11937-      switch (className) {
11938-        case boolClass:
11939-        case dateClass:
11940-          // coerce dates and booleans to numbers, dates to milliseconds and booleans
11941-          // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
11942-          return +a == +b;
11943-
11944-        case numberClass:
11945-          // treat `NaN` vs. `NaN` as equal
11946-          return (a != +a)
11947-            ? b != +b
11948-            // but treat `+0` vs. `-0` as not equal
11949-            : (a == 0 ? (1 / a == 1 / b) : a == +b);
11950-
11951-        case regexpClass:
11952-        case stringClass:
11953-          // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
11954-          // treat string primitives and their corresponding object instances as equal
11955-          return a == String(b);
11956-      }
11957-      var isArr = className == arrayClass;
11958-      if (!isArr) {
11959-        // unwrap any `lodash` wrapped values
11960-        var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
11961-          bWrapped = hasOwnProperty.call(b, '__wrapped__');
11962-
11963-        if (aWrapped || bWrapped) {
11964-          return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
11965-        }
11966-        // exit for functions and DOM nodes
11967-        if (className != objectClass) {
11968-          return false;
11969-        }
11970-        // in older versions of Opera, `arguments` objects have `Array` constructors
11971-        var ctorA = a.constructor,
11972-          ctorB = b.constructor;
11973-
11974-        // non `Object` object instances with different constructors are not equal
11975-        if (ctorA != ctorB &&
11976-          !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
11977-          ('constructor' in a && 'constructor' in b)
11978-        ) {
11979-          return false;
11980-        }
11981-      }
11982-      // assume cyclic structures are equal
11983-      // the algorithm for detecting cyclic structures is adapted from ES 5.1
11984-      // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
11985-      var initedStack = !stackA;
11986-      stackA || (stackA = getArray());
11987-      stackB || (stackB = getArray());
11988-
11989-      var length = stackA.length;
11990-      while (length--) {
11991-        if (stackA[length] == a) {
11992-          return stackB[length] == b;
11993-        }
11994-      }
11995-      var size = 0;
11996-      result = true;
11997-
11998-      // add `a` and `b` to the stack of traversed objects
11999-      stackA.push(a);
12000-      stackB.push(b);
12001-
12002-      // recursively compare objects and arrays (susceptible to call stack limits)
12003-      if (isArr) {
12004-        // compare lengths to determine if a deep comparison is necessary
12005-        length = a.length;
12006-        size = b.length;
12007-        result = size == length;
12008-
12009-        if (result || isWhere) {
12010-          // deep compare the contents, ignoring non-numeric properties
12011-          while (size--) {
12012-            var index = length,
12013-              value = b[size];
12014-
12015-            if (isWhere) {
12016-              while (index--) {
12017-                if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
12018-                  break;
12019-                }
12020-              }
12021-            } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
12022-              break;
12023-            }
12024-          }
12025-        }
12026-      }
12027-      else {
12028-        // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
12029-        // which, in this case, is more costly
12030-        forIn(b, function(value, key, b) {
12031-          if (hasOwnProperty.call(b, key)) {
12032-            // count the number of properties.
12033-            size++;
12034-            // deep compare each property value.
12035-            return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
12036-          }
12037-        });
12038-
12039-        if (result && !isWhere) {
12040-          // ensure both objects have the same number of properties
12041-          forIn(a, function(value, key, a) {
12042-            if (hasOwnProperty.call(a, key)) {
12043-              // `size` will be `-1` if `a` has more properties than `b`
12044-              return (result = --size > -1);
12045-            }
12046-          });
12047-        }
12048-      }
12049-      stackA.pop();
12050-      stackB.pop();
12051-
12052-      if (initedStack) {
12053-        releaseArray(stackA);
12054-        releaseArray(stackB);
12055-      }
12056-      return result;
12057-    }
12058-
12059-    /**
12060-     * The base implementation of `_.merge` without argument juggling or support
12061-     * for `thisArg` binding.
12062-     *
12063-     * @private
12064-     * @param {Object} object The destination object.
12065-     * @param {Object} source The source object.
12066-     * @param {Function} [callback] The function to customize merging properties.
12067-     * @param {Array} [stackA=[]] Tracks traversed source objects.
12068-     * @param {Array} [stackB=[]] Associates values with source counterparts.
12069-     */
12070-    function baseMerge(object, source, callback, stackA, stackB) {
12071-      (isArray(source) ? forEach : forOwn)(source, function(source, key) {
12072-        var found,
12073-          isArr,
12074-          result = source,
12075-          value = object[key];
12076-
12077-        if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
12078-          // avoid merging previously merged cyclic sources
12079-          var stackLength = stackA.length;
12080-          while (stackLength--) {
12081-            if ((found = stackA[stackLength] == source)) {
12082-              value = stackB[stackLength];
12083-              break;
12084-            }
12085-          }
12086-          if (!found) {
12087-            var isShallow;
12088-            if (callback) {
12089-              result = callback(value, source);
12090-              if ((isShallow = typeof result != 'undefined')) {
12091-                value = result;
12092-              }
12093-            }
12094-            if (!isShallow) {
12095-              value = isArr
12096-                ? (isArray(value) ? value : [])
12097-                : (isPlainObject(value) ? value : {});
12098-            }
12099-            // add `source` and associated `value` to the stack of traversed objects
12100-            stackA.push(source);
12101-            stackB.push(value);
12102-
12103-            // recursively merge objects and arrays (susceptible to call stack limits)
12104-            if (!isShallow) {
12105-              baseMerge(value, source, callback, stackA, stackB);
12106-            }
12107-          }
12108-        }
12109-        else {
12110-          if (callback) {
12111-            result = callback(value, source);
12112-            if (typeof result == 'undefined') {
12113-              result = source;
12114-            }
12115-          }
12116-          if (typeof result != 'undefined') {
12117-            value = result;
12118-          }
12119-        }
12120-        object[key] = value;
12121-      });
12122-    }
12123-
12124-    /**
12125-     * The base implementation of `_.random` without argument juggling or support
12126-     * for returning floating-point numbers.
12127-     *
12128-     * @private
12129-     * @param {number} min The minimum possible value.
12130-     * @param {number} max The maximum possible value.
12131-     * @returns {number} Returns a random number.
12132-     */
12133-    function baseRandom(min, max) {
12134-      return min + floor(nativeRandom() * (max - min + 1));
12135-    }
12136-
12137-    /**
12138-     * The base implementation of `_.uniq` without support for callback shorthands
12139-     * or `thisArg` binding.
12140-     *
12141-     * @private
12142-     * @param {Array} array The array to process.
12143-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
12144-     * @param {Function} [callback] The function called per iteration.
12145-     * @returns {Array} Returns a duplicate-value-free array.
12146-     */
12147-    function baseUniq(array, isSorted, callback) {
12148-      var index = -1,
12149-        indexOf = getIndexOf(),
12150-        length = array ? array.length : 0,
12151-        result = [];
12152-
12153-      var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
12154-        seen = (callback || isLarge) ? getArray() : result;
12155-
12156-      if (isLarge) {
12157-        var cache = createCache(seen);
12158-        indexOf = cacheIndexOf;
12159-        seen = cache;
12160-      }
12161-      while (++index < length) {
12162-        var value = array[index],
12163-          computed = callback ? callback(value, index, array) : value;
12164-
12165-        if (isSorted
12166-            ? !index || seen[seen.length - 1] !== computed
12167-            : indexOf(seen, computed) < 0
12168-        ) {
12169-          if (callback || isLarge) {
12170-            seen.push(computed);
12171-          }
12172-          result.push(value);
12173-        }
12174-      }
12175-      if (isLarge) {
12176-        releaseArray(seen.array);
12177-        releaseObject(seen);
12178-      } else if (callback) {
12179-        releaseArray(seen);
12180-      }
12181-      return result;
12182-    }
12183-
12184-    /**
12185-     * Creates a function that aggregates a collection, creating an object composed
12186-     * of keys generated from the results of running each element of the collection
12187-     * through a callback. The given `setter` function sets the keys and values
12188-     * of the composed object.
12189-     *
12190-     * @private
12191-     * @param {Function} setter The setter function.
12192-     * @returns {Function} Returns the new aggregator function.
12193-     */
12194-    function createAggregator(setter) {
12195-      return function(collection, callback, thisArg) {
12196-        var result = {};
12197-        callback = lodash.createCallback(callback, thisArg, 3);
12198-
12199-        var index = -1,
12200-          length = collection ? collection.length : 0;
12201-
12202-        if (typeof length == 'number') {
12203-          while (++index < length) {
12204-            var value = collection[index];
12205-            setter(result, value, callback(value, index, collection), collection);
12206-          }
12207-        } else {
12208-          forOwn(collection, function(value, key, collection) {
12209-            setter(result, value, callback(value, key, collection), collection);
12210-          });
12211-        }
12212-        return result;
12213-      };
12214-    }
12215-
12216-    /**
12217-     * Creates a function that, when called, either curries or invokes `func`
12218-     * with an optional `this` binding and partially applied arguments.
12219-     *
12220-     * @private
12221-     * @param {Function|string} func The function or method name to reference.
12222-     * @param {number} bitmask The bitmask of method flags to compose.
12223-     *  The bitmask may be composed of the following flags:
12224-     *  1 - `_.bind`
12225-     *  2 - `_.bindKey`
12226-     *  4 - `_.curry`
12227-     *  8 - `_.curry` (bound)
12228-     *  16 - `_.partial`
12229-     *  32 - `_.partialRight`
12230-     * @param {Array} [partialArgs] An array of arguments to prepend to those
12231-     *  provided to the new function.
12232-     * @param {Array} [partialRightArgs] An array of arguments to append to those
12233-     *  provided to the new function.
12234-     * @param {*} [thisArg] The `this` binding of `func`.
12235-     * @param {number} [arity] The arity of `func`.
12236-     * @returns {Function} Returns the new function.
12237-     */
12238-    function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
12239-      var isBind = bitmask & 1,
12240-        isBindKey = bitmask & 2,
12241-        isCurry = bitmask & 4,
12242-        isCurryBound = bitmask & 8,
12243-        isPartial = bitmask & 16,
12244-        isPartialRight = bitmask & 32;
12245-
12246-      if (!isBindKey && !isFunction(func)) {
12247-        throw new TypeError;
12248-      }
12249-      if (isPartial && !partialArgs.length) {
12250-        bitmask &= ~16;
12251-        isPartial = partialArgs = false;
12252-      }
12253-      if (isPartialRight && !partialRightArgs.length) {
12254-        bitmask &= ~32;
12255-        isPartialRight = partialRightArgs = false;
12256-      }
12257-      var bindData = func && func.__bindData__;
12258-      if (bindData && bindData !== true) {
12259-        // clone `bindData`
12260-        bindData = slice(bindData);
12261-        if (bindData[2]) {
12262-          bindData[2] = slice(bindData[2]);
12263-        }
12264-        if (bindData[3]) {
12265-          bindData[3] = slice(bindData[3]);
12266-        }
12267-        // set `thisBinding` is not previously bound
12268-        if (isBind && !(bindData[1] & 1)) {
12269-          bindData[4] = thisArg;
12270-        }
12271-        // set if previously bound but not currently (subsequent curried functions)
12272-        if (!isBind && bindData[1] & 1) {
12273-          bitmask |= 8;
12274-        }
12275-        // set curried arity if not yet set
12276-        if (isCurry && !(bindData[1] & 4)) {
12277-          bindData[5] = arity;
12278-        }
12279-        // append partial left arguments
12280-        if (isPartial) {
12281-          push.apply(bindData[2] || (bindData[2] = []), partialArgs);
12282-        }
12283-        // append partial right arguments
12284-        if (isPartialRight) {
12285-          unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
12286-        }
12287-        // merge flags
12288-        bindData[1] |= bitmask;
12289-        return createWrapper.apply(null, bindData);
12290-      }
12291-      // fast path for `_.bind`
12292-      var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
12293-      return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
12294-    }
12295-
12296-    /**
12297-     * Used by `escape` to convert characters to HTML entities.
12298-     *
12299-     * @private
12300-     * @param {string} match The matched character to escape.
12301-     * @returns {string} Returns the escaped character.
12302-     */
12303-    function escapeHtmlChar(match) {
12304-      return htmlEscapes[match];
12305-    }
12306-
12307-    /**
12308-     * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
12309-     * customized, this method returns the custom method, otherwise it returns
12310-     * the `baseIndexOf` function.
12311-     *
12312-     * @private
12313-     * @returns {Function} Returns the "indexOf" function.
12314-     */
12315-    function getIndexOf() {
12316-      var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
12317-      return result;
12318-    }
12319-
12320-    /**
12321-     * Checks if `value` is a native function.
12322-     *
12323-     * @private
12324-     * @param {*} value The value to check.
12325-     * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
12326-     */
12327-    function isNative(value) {
12328-      return typeof value == 'function' && reNative.test(value);
12329-    }
12330-
12331-    /**
12332-     * Sets `this` binding data on a given function.
12333-     *
12334-     * @private
12335-     * @param {Function} func The function to set data on.
12336-     * @param {Array} value The data array to set.
12337-     */
12338-    var setBindData = !defineProperty ? noop : function(func, value) {
12339-      descriptor.value = value;
12340-      defineProperty(func, '__bindData__', descriptor);
12341-    };
12342-
12343-    /**
12344-     * A fallback implementation of `isPlainObject` which checks if a given value
12345-     * is an object created by the `Object` constructor, assuming objects created
12346-     * by the `Object` constructor have no inherited enumerable properties and that
12347-     * there are no `Object.prototype` extensions.
12348-     *
12349-     * @private
12350-     * @param {*} value The value to check.
12351-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
12352-     */
12353-    function shimIsPlainObject(value) {
12354-      var ctor,
12355-        result;
12356-
12357-      // avoid non Object objects, `arguments` objects, and DOM elements
12358-      if (!(value && toString.call(value) == objectClass) ||
12359-        (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
12360-        return false;
12361-      }
12362-      // In most environments an object's own properties are iterated before
12363-      // its inherited properties. If the last iterated property is an object's
12364-      // own property then there are no inherited enumerable properties.
12365-      forIn(value, function(value, key) {
12366-        result = key;
12367-      });
12368-      return typeof result == 'undefined' || hasOwnProperty.call(value, result);
12369-    }
12370-
12371-    /**
12372-     * Used by `unescape` to convert HTML entities to characters.
12373-     *
12374-     * @private
12375-     * @param {string} match The matched character to unescape.
12376-     * @returns {string} Returns the unescaped character.
12377-     */
12378-    function unescapeHtmlChar(match) {
12379-      return htmlUnescapes[match];
12380-    }
12381-
12382-    /*--------------------------------------------------------------------------*/
12383-
12384-    /**
12385-     * Checks if `value` is an `arguments` object.
12386-     *
12387-     * @static
12388-     * @memberOf _
12389-     * @category Objects
12390-     * @param {*} value The value to check.
12391-     * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
12392-     * @example
12393-     *
12394-     * (function() { return _.isArguments(arguments); })(1, 2, 3);
12395-     * // => true
12396-     *
12397-     * _.isArguments([1, 2, 3]);
12398-     * // => false
12399-     */
12400-    function isArguments(value) {
12401-      return value && typeof value == 'object' && typeof value.length == 'number' &&
12402-        toString.call(value) == argsClass || false;
12403-    }
12404-
12405-    /**
12406-     * Checks if `value` is an array.
12407-     *
12408-     * @static
12409-     * @memberOf _
12410-     * @type Function
12411-     * @category Objects
12412-     * @param {*} value The value to check.
12413-     * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
12414-     * @example
12415-     *
12416-     * (function() { return _.isArray(arguments); })();
12417-     * // => false
12418-     *
12419-     * _.isArray([1, 2, 3]);
12420-     * // => true
12421-     */
12422-    var isArray = nativeIsArray || function(value) {
12423-        return value && typeof value == 'object' && typeof value.length == 'number' &&
12424-          toString.call(value) == arrayClass || false;
12425-      };
12426-
12427-    /**
12428-     * A fallback implementation of `Object.keys` which produces an array of the
12429-     * given object's own enumerable property names.
12430-     *
12431-     * @private
12432-     * @type Function
12433-     * @param {Object} object The object to inspect.
12434-     * @returns {Array} Returns an array of property names.
12435-     */
12436-    var shimKeys = function(object) {
12437-      var index, iterable = object, result = [];
12438-      if (!iterable) return result;
12439-      if (!(objectTypes[typeof object])) return result;
12440-      for (index in iterable) {
12441-        if (hasOwnProperty.call(iterable, index)) {
12442-          result.push(index);
12443-        }
12444-      }
12445-      return result
12446-    };
12447-
12448-    /**
12449-     * Creates an array composed of the own enumerable property names of an object.
12450-     *
12451-     * @static
12452-     * @memberOf _
12453-     * @category Objects
12454-     * @param {Object} object The object to inspect.
12455-     * @returns {Array} Returns an array of property names.
12456-     * @example
12457-     *
12458-     * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
12459-     * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
12460-     */
12461-    var keys = !nativeKeys ? shimKeys : function(object) {
12462-      if (!isObject(object)) {
12463-        return [];
12464-      }
12465-      return nativeKeys(object);
12466-    };
12467-
12468-    /**
12469-     * Used to convert characters to HTML entities:
12470-     *
12471-     * Though the `>` character is escaped for symmetry, characters like `>` and `/`
12472-     * don't require escaping in HTML and have no special meaning unless they're part
12473-     * of a tag or an unquoted attribute value.
12474-     * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
12475-     */
12476-    var htmlEscapes = {
12477-      '&': '&amp;',
12478-      '<': '&lt;',
12479-      '>': '&gt;',
12480-      '"': '&quot;',
12481-      "'": '&#39;'
12482-    };
12483-
12484-    /** Used to convert HTML entities to characters */
12485-    var htmlUnescapes = invert(htmlEscapes);
12486-
12487-    /** Used to match HTML entities and HTML characters */
12488-    var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
12489-      reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
12490-
12491-    /*--------------------------------------------------------------------------*/
12492-
12493-    /**
12494-     * Assigns own enumerable properties of source object(s) to the destination
12495-     * object. Subsequent sources will overwrite property assignments of previous
12496-     * sources. If a callback is provided it will be executed to produce the
12497-     * assigned values. The callback is bound to `thisArg` and invoked with two
12498-     * arguments; (objectValue, sourceValue).
12499-     *
12500-     * @static
12501-     * @memberOf _
12502-     * @type Function
12503-     * @alias extend
12504-     * @category Objects
12505-     * @param {Object} object The destination object.
12506-     * @param {...Object} [source] The source objects.
12507-     * @param {Function} [callback] The function to customize assigning values.
12508-     * @param {*} [thisArg] The `this` binding of `callback`.
12509-     * @returns {Object} Returns the destination object.
12510-     * @example
12511-     *
12512-     * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
12513-     * // => { 'name': 'fred', 'employer': 'slate' }
12514-     *
12515-     * var defaults = _.partialRight(_.assign, function(a, b) {
12516-     *   return typeof a == 'undefined' ? b : a;
12517-     * });
12518-     *
12519-     * var object = { 'name': 'barney' };
12520-     * defaults(object, { 'name': 'fred', 'employer': 'slate' });
12521-     * // => { 'name': 'barney', 'employer': 'slate' }
12522-     */
12523-    var assign = function(object, source, guard) {
12524-      var index, iterable = object, result = iterable;
12525-      if (!iterable) return result;
12526-      var args = arguments,
12527-        argsIndex = 0,
12528-        argsLength = typeof guard == 'number' ? 2 : args.length;
12529-      if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
12530-        var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
12531-      } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
12532-        callback = args[--argsLength];
12533-      }
12534-      while (++argsIndex < argsLength) {
12535-        iterable = args[argsIndex];
12536-        if (iterable && objectTypes[typeof iterable]) {
12537-          var ownIndex = -1,
12538-            ownProps = objectTypes[typeof iterable] && keys(iterable),
12539-            length = ownProps ? ownProps.length : 0;
12540-
12541-          while (++ownIndex < length) {
12542-            index = ownProps[ownIndex];
12543-            result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
12544-          }
12545-        }
12546-      }
12547-      return result
12548-    };
12549-
12550-    /**
12551-     * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
12552-     * be cloned, otherwise they will be assigned by reference. If a callback
12553-     * is provided it will be executed to produce the cloned values. If the
12554-     * callback returns `undefined` cloning will be handled by the method instead.
12555-     * The callback is bound to `thisArg` and invoked with one argument; (value).
12556-     *
12557-     * @static
12558-     * @memberOf _
12559-     * @category Objects
12560-     * @param {*} value The value to clone.
12561-     * @param {boolean} [isDeep=false] Specify a deep clone.
12562-     * @param {Function} [callback] The function to customize cloning values.
12563-     * @param {*} [thisArg] The `this` binding of `callback`.
12564-     * @returns {*} Returns the cloned value.
12565-     * @example
12566-     *
12567-     * var characters = [
12568-     *   { 'name': 'barney', 'age': 36 },
12569-     *   { 'name': 'fred',   'age': 40 }
12570-     * ];
12571-     *
12572-     * var shallow = _.clone(characters);
12573-     * shallow[0] === characters[0];
12574-     * // => true
12575-     *
12576-     * var deep = _.clone(characters, true);
12577-     * deep[0] === characters[0];
12578-     * // => false
12579-     *
12580-     * _.mixin({
12581-     *   'clone': _.partialRight(_.clone, function(value) {
12582-     *     return _.isElement(value) ? value.cloneNode(false) : undefined;
12583-     *   })
12584-     * });
12585-     *
12586-     * var clone = _.clone(document.body);
12587-     * clone.childNodes.length;
12588-     * // => 0
12589-     */
12590-    function clone(value, isDeep, callback, thisArg) {
12591-      // allows working with "Collections" methods without using their `index`
12592-      // and `collection` arguments for `isDeep` and `callback`
12593-      if (typeof isDeep != 'boolean' && isDeep != null) {
12594-        thisArg = callback;
12595-        callback = isDeep;
12596-        isDeep = false;
12597-      }
12598-      return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
12599-    }
12600-
12601-    /**
12602-     * Creates a deep clone of `value`. If a callback is provided it will be
12603-     * executed to produce the cloned values. If the callback returns `undefined`
12604-     * cloning will be handled by the method instead. The callback is bound to
12605-     * `thisArg` and invoked with one argument; (value).
12606-     *
12607-     * Note: This method is loosely based on the structured clone algorithm. Functions
12608-     * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
12609-     * objects created by constructors other than `Object` are cloned to plain `Object` objects.
12610-     * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
12611-     *
12612-     * @static
12613-     * @memberOf _
12614-     * @category Objects
12615-     * @param {*} value The value to deep clone.
12616-     * @param {Function} [callback] The function to customize cloning values.
12617-     * @param {*} [thisArg] The `this` binding of `callback`.
12618-     * @returns {*} Returns the deep cloned value.
12619-     * @example
12620-     *
12621-     * var characters = [
12622-     *   { 'name': 'barney', 'age': 36 },
12623-     *   { 'name': 'fred',   'age': 40 }
12624-     * ];
12625-     *
12626-     * var deep = _.cloneDeep(characters);
12627-     * deep[0] === characters[0];
12628-     * // => false
12629-     *
12630-     * var view = {
12631-     *   'label': 'docs',
12632-     *   'node': element
12633-     * };
12634-     *
12635-     * var clone = _.cloneDeep(view, function(value) {
12636-     *   return _.isElement(value) ? value.cloneNode(true) : undefined;
12637-     * });
12638-     *
12639-     * clone.node == view.node;
12640-     * // => false
12641-     */
12642-    function cloneDeep(value, callback, thisArg) {
12643-      return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
12644-    }
12645-
12646-    /**
12647-     * Creates an object that inherits from the given `prototype` object. If a
12648-     * `properties` object is provided its own enumerable properties are assigned
12649-     * to the created object.
12650-     *
12651-     * @static
12652-     * @memberOf _
12653-     * @category Objects
12654-     * @param {Object} prototype The object to inherit from.
12655-     * @param {Object} [properties] The properties to assign to the object.
12656-     * @returns {Object} Returns the new object.
12657-     * @example
12658-     *
12659-     * function Shape() {
12660-     *   this.x = 0;
12661-     *   this.y = 0;
12662-     * }
12663-     *
12664-     * function Circle() {
12665-     *   Shape.call(this);
12666-     * }
12667-     *
12668-     * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
12669-     *
12670-     * var circle = new Circle;
12671-     * circle instanceof Circle;
12672-     * // => true
12673-     *
12674-     * circle instanceof Shape;
12675-     * // => true
12676-     */
12677-    function create(prototype, properties) {
12678-      var result = baseCreate(prototype);
12679-      return properties ? assign(result, properties) : result;
12680-    }
12681-
12682-    /**
12683-     * Assigns own enumerable properties of source object(s) to the destination
12684-     * object for all destination properties that resolve to `undefined`. Once a
12685-     * property is set, additional defaults of the same property will be ignored.
12686-     *
12687-     * @static
12688-     * @memberOf _
12689-     * @type Function
12690-     * @category Objects
12691-     * @param {Object} object The destination object.
12692-     * @param {...Object} [source] The source objects.
12693-     * @param- {Object} [guard] Allows working with `_.reduce` without using its
12694-     *  `key` and `object` arguments as sources.
12695-     * @returns {Object} Returns the destination object.
12696-     * @example
12697-     *
12698-     * var object = { 'name': 'barney' };
12699-     * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
12700-     * // => { 'name': 'barney', 'employer': 'slate' }
12701-     */
12702-    var defaults = function(object, source, guard) {
12703-      var index, iterable = object, result = iterable;
12704-      if (!iterable) return result;
12705-      var args = arguments,
12706-        argsIndex = 0,
12707-        argsLength = typeof guard == 'number' ? 2 : args.length;
12708-      while (++argsIndex < argsLength) {
12709-        iterable = args[argsIndex];
12710-        if (iterable && objectTypes[typeof iterable]) {
12711-          var ownIndex = -1,
12712-            ownProps = objectTypes[typeof iterable] && keys(iterable),
12713-            length = ownProps ? ownProps.length : 0;
12714-
12715-          while (++ownIndex < length) {
12716-            index = ownProps[ownIndex];
12717-            if (typeof result[index] == 'undefined') result[index] = iterable[index];
12718-          }
12719-        }
12720-      }
12721-      return result
12722-    };
12723-
12724-    /**
12725-     * This method is like `_.findIndex` except that it returns the key of the
12726-     * first element that passes the callback check, instead of the element itself.
12727-     *
12728-     * If a property name is provided for `callback` the created "_.pluck" style
12729-     * callback will return the property value of the given element.
12730-     *
12731-     * If an object is provided for `callback` the created "_.where" style callback
12732-     * will return `true` for elements that have the properties of the given object,
12733-     * else `false`.
12734-     *
12735-     * @static
12736-     * @memberOf _
12737-     * @category Objects
12738-     * @param {Object} object The object to search.
12739-     * @param {Function|Object|string} [callback=identity] The function called per
12740-     *  iteration. If a property name or object is provided it will be used to
12741-     *  create a "_.pluck" or "_.where" style callback, respectively.
12742-     * @param {*} [thisArg] The `this` binding of `callback`.
12743-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
12744-     * @example
12745-     *
12746-     * var characters = {
12747-     *   'barney': {  'age': 36, 'blocked': false },
12748-     *   'fred': {    'age': 40, 'blocked': true },
12749-     *   'pebbles': { 'age': 1,  'blocked': false }
12750-     * };
12751-     *
12752-     * _.findKey(characters, function(chr) {
12753-     *   return chr.age < 40;
12754-     * });
12755-     * // => 'barney' (property order is not guaranteed across environments)
12756-     *
12757-     * // using "_.where" callback shorthand
12758-     * _.findKey(characters, { 'age': 1 });
12759-     * // => 'pebbles'
12760-     *
12761-     * // using "_.pluck" callback shorthand
12762-     * _.findKey(characters, 'blocked');
12763-     * // => 'fred'
12764-     */
12765-    function findKey(object, callback, thisArg) {
12766-      var result;
12767-      callback = lodash.createCallback(callback, thisArg, 3);
12768-      forOwn(object, function(value, key, object) {
12769-        if (callback(value, key, object)) {
12770-          result = key;
12771-          return false;
12772-        }
12773-      });
12774-      return result;
12775-    }
12776-
12777-    /**
12778-     * This method is like `_.findKey` except that it iterates over elements
12779-     * of a `collection` in the opposite order.
12780-     *
12781-     * If a property name is provided for `callback` the created "_.pluck" style
12782-     * callback will return the property value of the given element.
12783-     *
12784-     * If an object is provided for `callback` the created "_.where" style callback
12785-     * will return `true` for elements that have the properties of the given object,
12786-     * else `false`.
12787-     *
12788-     * @static
12789-     * @memberOf _
12790-     * @category Objects
12791-     * @param {Object} object The object to search.
12792-     * @param {Function|Object|string} [callback=identity] The function called per
12793-     *  iteration. If a property name or object is provided it will be used to
12794-     *  create a "_.pluck" or "_.where" style callback, respectively.
12795-     * @param {*} [thisArg] The `this` binding of `callback`.
12796-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
12797-     * @example
12798-     *
12799-     * var characters = {
12800-     *   'barney': {  'age': 36, 'blocked': true },
12801-     *   'fred': {    'age': 40, 'blocked': false },
12802-     *   'pebbles': { 'age': 1,  'blocked': true }
12803-     * };
12804-     *
12805-     * _.findLastKey(characters, function(chr) {
12806-     *   return chr.age < 40;
12807-     * });
12808-     * // => returns `pebbles`, assuming `_.findKey` returns `barney`
12809-     *
12810-     * // using "_.where" callback shorthand
12811-     * _.findLastKey(characters, { 'age': 40 });
12812-     * // => 'fred'
12813-     *
12814-     * // using "_.pluck" callback shorthand
12815-     * _.findLastKey(characters, 'blocked');
12816-     * // => 'pebbles'
12817-     */
12818-    function findLastKey(object, callback, thisArg) {
12819-      var result;
12820-      callback = lodash.createCallback(callback, thisArg, 3);
12821-      forOwnRight(object, function(value, key, object) {
12822-        if (callback(value, key, object)) {
12823-          result = key;
12824-          return false;
12825-        }
12826-      });
12827-      return result;
12828-    }
12829-
12830-    /**
12831-     * Iterates over own and inherited enumerable properties of an object,
12832-     * executing the callback for each property. The callback is bound to `thisArg`
12833-     * and invoked with three arguments; (value, key, object). Callbacks may exit
12834-     * iteration early by explicitly returning `false`.
12835-     *
12836-     * @static
12837-     * @memberOf _
12838-     * @type Function
12839-     * @category Objects
12840-     * @param {Object} object The object to iterate over.
12841-     * @param {Function} [callback=identity] The function called per iteration.
12842-     * @param {*} [thisArg] The `this` binding of `callback`.
12843-     * @returns {Object} Returns `object`.
12844-     * @example
12845-     *
12846-     * function Shape() {
12847-     *   this.x = 0;
12848-     *   this.y = 0;
12849-     * }
12850-     *
12851-     * Shape.prototype.move = function(x, y) {
12852-     *   this.x += x;
12853-     *   this.y += y;
12854-     * };
12855-     *
12856-     * _.forIn(new Shape, function(value, key) {
12857-     *   console.log(key);
12858-     * });
12859-     * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
12860-     */
12861-    var forIn = function(collection, callback, thisArg) {
12862-      var index, iterable = collection, result = iterable;
12863-      if (!iterable) return result;
12864-      if (!objectTypes[typeof iterable]) return result;
12865-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
12866-      for (index in iterable) {
12867-        if (callback(iterable[index], index, collection) === false) return result;
12868-      }
12869-      return result
12870-    };
12871-
12872-    /**
12873-     * This method is like `_.forIn` except that it iterates over elements
12874-     * of a `collection` in the opposite order.
12875-     *
12876-     * @static
12877-     * @memberOf _
12878-     * @category Objects
12879-     * @param {Object} object The object to iterate over.
12880-     * @param {Function} [callback=identity] The function called per iteration.
12881-     * @param {*} [thisArg] The `this` binding of `callback`.
12882-     * @returns {Object} Returns `object`.
12883-     * @example
12884-     *
12885-     * function Shape() {
12886-     *   this.x = 0;
12887-     *   this.y = 0;
12888-     * }
12889-     *
12890-     * Shape.prototype.move = function(x, y) {
12891-     *   this.x += x;
12892-     *   this.y += y;
12893-     * };
12894-     *
12895-     * _.forInRight(new Shape, function(value, key) {
12896-     *   console.log(key);
12897-     * });
12898-     * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
12899-     */
12900-    function forInRight(object, callback, thisArg) {
12901-      var pairs = [];
12902-
12903-      forIn(object, function(value, key) {
12904-        pairs.push(key, value);
12905-      });
12906-
12907-      var length = pairs.length;
12908-      callback = baseCreateCallback(callback, thisArg, 3);
12909-      while (length--) {
12910-        if (callback(pairs[length--], pairs[length], object) === false) {
12911-          break;
12912-        }
12913-      }
12914-      return object;
12915-    }
12916-
12917-    /**
12918-     * Iterates over own enumerable properties of an object, executing the callback
12919-     * for each property. The callback is bound to `thisArg` and invoked with three
12920-     * arguments; (value, key, object). Callbacks may exit iteration early by
12921-     * explicitly returning `false`.
12922-     *
12923-     * @static
12924-     * @memberOf _
12925-     * @type Function
12926-     * @category Objects
12927-     * @param {Object} object The object to iterate over.
12928-     * @param {Function} [callback=identity] The function called per iteration.
12929-     * @param {*} [thisArg] The `this` binding of `callback`.
12930-     * @returns {Object} Returns `object`.
12931-     * @example
12932-     *
12933-     * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
12934-     *   console.log(key);
12935-     * });
12936-     * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
12937-     */
12938-    var forOwn = function(collection, callback, thisArg) {
12939-      var index, iterable = collection, result = iterable;
12940-      if (!iterable) return result;
12941-      if (!objectTypes[typeof iterable]) return result;
12942-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
12943-      var ownIndex = -1,
12944-        ownProps = objectTypes[typeof iterable] && keys(iterable),
12945-        length = ownProps ? ownProps.length : 0;
12946-
12947-      while (++ownIndex < length) {
12948-        index = ownProps[ownIndex];
12949-        if (callback(iterable[index], index, collection) === false) return result;
12950-      }
12951-      return result
12952-    };
12953-
12954-    /**
12955-     * This method is like `_.forOwn` except that it iterates over elements
12956-     * of a `collection` in the opposite order.
12957-     *
12958-     * @static
12959-     * @memberOf _
12960-     * @category Objects
12961-     * @param {Object} object The object to iterate over.
12962-     * @param {Function} [callback=identity] The function called per iteration.
12963-     * @param {*} [thisArg] The `this` binding of `callback`.
12964-     * @returns {Object} Returns `object`.
12965-     * @example
12966-     *
12967-     * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
12968-     *   console.log(key);
12969-     * });
12970-     * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
12971-     */
12972-    function forOwnRight(object, callback, thisArg) {
12973-      var props = keys(object),
12974-        length = props.length;
12975-
12976-      callback = baseCreateCallback(callback, thisArg, 3);
12977-      while (length--) {
12978-        var key = props[length];
12979-        if (callback(object[key], key, object) === false) {
12980-          break;
12981-        }
12982-      }
12983-      return object;
12984-    }
12985-
12986-    /**
12987-     * Creates a sorted array of property names of all enumerable properties,
12988-     * own and inherited, of `object` that have function values.
12989-     *
12990-     * @static
12991-     * @memberOf _
12992-     * @alias methods
12993-     * @category Objects
12994-     * @param {Object} object The object to inspect.
12995-     * @returns {Array} Returns an array of property names that have function values.
12996-     * @example
12997-     *
12998-     * _.functions(_);
12999-     * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
13000-     */
13001-    function functions(object) {
13002-      var result = [];
13003-      forIn(object, function(value, key) {
13004-        if (isFunction(value)) {
13005-          result.push(key);
13006-        }
13007-      });
13008-      return result.sort();
13009-    }
13010-
13011-    /**
13012-     * Checks if the specified property name exists as a direct property of `object`,
13013-     * instead of an inherited property.
13014-     *
13015-     * @static
13016-     * @memberOf _
13017-     * @category Objects
13018-     * @param {Object} object The object to inspect.
13019-     * @param {string} key The name of the property to check.
13020-     * @returns {boolean} Returns `true` if key is a direct property, else `false`.
13021-     * @example
13022-     *
13023-     * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
13024-     * // => true
13025-     */
13026-    function has(object, key) {
13027-      return object ? hasOwnProperty.call(object, key) : false;
13028-    }
13029-
13030-    /**
13031-     * Creates an object composed of the inverted keys and values of the given object.
13032-     *
13033-     * @static
13034-     * @memberOf _
13035-     * @category Objects
13036-     * @param {Object} object The object to invert.
13037-     * @returns {Object} Returns the created inverted object.
13038-     * @example
13039-     *
13040-     * _.invert({ 'first': 'fred', 'second': 'barney' });
13041-     * // => { 'fred': 'first', 'barney': 'second' }
13042-     */
13043-    function invert(object) {
13044-      var index = -1,
13045-        props = keys(object),
13046-        length = props.length,
13047-        result = {};
13048-
13049-      while (++index < length) {
13050-        var key = props[index];
13051-        result[object[key]] = key;
13052-      }
13053-      return result;
13054-    }
13055-
13056-    /**
13057-     * Checks if `value` is a boolean value.
13058-     *
13059-     * @static
13060-     * @memberOf _
13061-     * @category Objects
13062-     * @param {*} value The value to check.
13063-     * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
13064-     * @example
13065-     *
13066-     * _.isBoolean(null);
13067-     * // => false
13068-     */
13069-    function isBoolean(value) {
13070-      return value === true || value === false ||
13071-        value && typeof value == 'object' && toString.call(value) == boolClass || false;
13072-    }
13073-
13074-    /**
13075-     * Checks if `value` is a date.
13076-     *
13077-     * @static
13078-     * @memberOf _
13079-     * @category Objects
13080-     * @param {*} value The value to check.
13081-     * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
13082-     * @example
13083-     *
13084-     * _.isDate(new Date);
13085-     * // => true
13086-     */
13087-    function isDate(value) {
13088-      return value && typeof value == 'object' && toString.call(value) == dateClass || false;
13089-    }
13090-
13091-    /**
13092-     * Checks if `value` is a DOM element.
13093-     *
13094-     * @static
13095-     * @memberOf _
13096-     * @category Objects
13097-     * @param {*} value The value to check.
13098-     * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
13099-     * @example
13100-     *
13101-     * _.isElement(document.body);
13102-     * // => true
13103-     */
13104-    function isElement(value) {
13105-      return value && value.nodeType === 1 || false;
13106-    }
13107-
13108-    /**
13109-     * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
13110-     * length of `0` and objects with no own enumerable properties are considered
13111-     * "empty".
13112-     *
13113-     * @static
13114-     * @memberOf _
13115-     * @category Objects
13116-     * @param {Array|Object|string} value The value to inspect.
13117-     * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
13118-     * @example
13119-     *
13120-     * _.isEmpty([1, 2, 3]);
13121-     * // => false
13122-     *
13123-     * _.isEmpty({});
13124-     * // => true
13125-     *
13126-     * _.isEmpty('');
13127-     * // => true
13128-     */
13129-    function isEmpty(value) {
13130-      var result = true;
13131-      if (!value) {
13132-        return result;
13133-      }
13134-      var className = toString.call(value),
13135-        length = value.length;
13136-
13137-      if ((className == arrayClass || className == stringClass || className == argsClass ) ||
13138-        (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
13139-        return !length;
13140-      }
13141-      forOwn(value, function() {
13142-        return (result = false);
13143-      });
13144-      return result;
13145-    }
13146-
13147-    /**
13148-     * Performs a deep comparison between two values to determine if they are
13149-     * equivalent to each other. If a callback is provided it will be executed
13150-     * to compare values. If the callback returns `undefined` comparisons will
13151-     * be handled by the method instead. The callback is bound to `thisArg` and
13152-     * invoked with two arguments; (a, b).
13153-     *
13154-     * @static
13155-     * @memberOf _
13156-     * @category Objects
13157-     * @param {*} a The value to compare.
13158-     * @param {*} b The other value to compare.
13159-     * @param {Function} [callback] The function to customize comparing values.
13160-     * @param {*} [thisArg] The `this` binding of `callback`.
13161-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
13162-     * @example
13163-     *
13164-     * var object = { 'name': 'fred' };
13165-     * var copy = { 'name': 'fred' };
13166-     *
13167-     * object == copy;
13168-     * // => false
13169-     *
13170-     * _.isEqual(object, copy);
13171-     * // => true
13172-     *
13173-     * var words = ['hello', 'goodbye'];
13174-     * var otherWords = ['hi', 'goodbye'];
13175-     *
13176-     * _.isEqual(words, otherWords, function(a, b) {
13177-     *   var reGreet = /^(?:hello|hi)$/i,
13178-     *       aGreet = _.isString(a) && reGreet.test(a),
13179-     *       bGreet = _.isString(b) && reGreet.test(b);
13180-     *
13181-     *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
13182-     * });
13183-     * // => true
13184-     */
13185-    function isEqual(a, b, callback, thisArg) {
13186-      return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
13187-    }
13188-
13189-    /**
13190-     * Checks if `value` is, or can be coerced to, a finite number.
13191-     *
13192-     * Note: This is not the same as native `isFinite` which will return true for
13193-     * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
13194-     *
13195-     * @static
13196-     * @memberOf _
13197-     * @category Objects
13198-     * @param {*} value The value to check.
13199-     * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
13200-     * @example
13201-     *
13202-     * _.isFinite(-101);
13203-     * // => true
13204-     *
13205-     * _.isFinite('10');
13206-     * // => true
13207-     *
13208-     * _.isFinite(true);
13209-     * // => false
13210-     *
13211-     * _.isFinite('');
13212-     * // => false
13213-     *
13214-     * _.isFinite(Infinity);
13215-     * // => false
13216-     */
13217-    function isFinite(value) {
13218-      return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
13219-    }
13220-
13221-    /**
13222-     * Checks if `value` is a function.
13223-     *
13224-     * @static
13225-     * @memberOf _
13226-     * @category Objects
13227-     * @param {*} value The value to check.
13228-     * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
13229-     * @example
13230-     *
13231-     * _.isFunction(_);
13232-     * // => true
13233-     */
13234-    function isFunction(value) {
13235-      return typeof value == 'function';
13236-    }
13237-
13238-    /**
13239-     * Checks if `value` is the language type of Object.
13240-     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
13241-     *
13242-     * @static
13243-     * @memberOf _
13244-     * @category Objects
13245-     * @param {*} value The value to check.
13246-     * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
13247-     * @example
13248-     *
13249-     * _.isObject({});
13250-     * // => true
13251-     *
13252-     * _.isObject([1, 2, 3]);
13253-     * // => true
13254-     *
13255-     * _.isObject(1);
13256-     * // => false
13257-     */
13258-    function isObject(value) {
13259-      // check if the value is the ECMAScript language type of Object
13260-      // http://es5.github.io/#x8
13261-      // and avoid a V8 bug
13262-      // http://code.google.com/p/v8/issues/detail?id=2291
13263-      return !!(value && objectTypes[typeof value]);
13264-    }
13265-
13266-    /**
13267-     * Checks if `value` is `NaN`.
13268-     *
13269-     * Note: This is not the same as native `isNaN` which will return `true` for
13270-     * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
13271-     *
13272-     * @static
13273-     * @memberOf _
13274-     * @category Objects
13275-     * @param {*} value The value to check.
13276-     * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
13277-     * @example
13278-     *
13279-     * _.isNaN(NaN);
13280-     * // => true
13281-     *
13282-     * _.isNaN(new Number(NaN));
13283-     * // => true
13284-     *
13285-     * isNaN(undefined);
13286-     * // => true
13287-     *
13288-     * _.isNaN(undefined);
13289-     * // => false
13290-     */
13291-    function isNaN(value) {
13292-      // `NaN` as a primitive is the only value that is not equal to itself
13293-      // (perform the [[Class]] check first to avoid errors with some host objects in IE)
13294-      return isNumber(value) && value != +value;
13295-    }
13296-
13297-    /**
13298-     * Checks if `value` is `null`.
13299-     *
13300-     * @static
13301-     * @memberOf _
13302-     * @category Objects
13303-     * @param {*} value The value to check.
13304-     * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
13305-     * @example
13306-     *
13307-     * _.isNull(null);
13308-     * // => true
13309-     *
13310-     * _.isNull(undefined);
13311-     * // => false
13312-     */
13313-    function isNull(value) {
13314-      return value === null;
13315-    }
13316-
13317-    /**
13318-     * Checks if `value` is a number.
13319-     *
13320-     * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
13321-     *
13322-     * @static
13323-     * @memberOf _
13324-     * @category Objects
13325-     * @param {*} value The value to check.
13326-     * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
13327-     * @example
13328-     *
13329-     * _.isNumber(8.4 * 5);
13330-     * // => true
13331-     */
13332-    function isNumber(value) {
13333-      return typeof value == 'number' ||
13334-        value && typeof value == 'object' && toString.call(value) == numberClass || false;
13335-    }
13336-
13337-    /**
13338-     * Checks if `value` is an object created by the `Object` constructor.
13339-     *
13340-     * @static
13341-     * @memberOf _
13342-     * @category Objects
13343-     * @param {*} value The value to check.
13344-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
13345-     * @example
13346-     *
13347-     * function Shape() {
13348-     *   this.x = 0;
13349-     *   this.y = 0;
13350-     * }
13351-     *
13352-     * _.isPlainObject(new Shape);
13353-     * // => false
13354-     *
13355-     * _.isPlainObject([1, 2, 3]);
13356-     * // => false
13357-     *
13358-     * _.isPlainObject({ 'x': 0, 'y': 0 });
13359-     * // => true
13360-     */
13361-    var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
13362-      if (!(value && toString.call(value) == objectClass)) {
13363-        return false;
13364-      }
13365-      var valueOf = value.valueOf,
13366-        objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
13367-
13368-      return objProto
13369-        ? (value == objProto || getPrototypeOf(value) == objProto)
13370-        : shimIsPlainObject(value);
13371-    };
13372-
13373-    /**
13374-     * Checks if `value` is a regular expression.
13375-     *
13376-     * @static
13377-     * @memberOf _
13378-     * @category Objects
13379-     * @param {*} value The value to check.
13380-     * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
13381-     * @example
13382-     *
13383-     * _.isRegExp(/fred/);
13384-     * // => true
13385-     */
13386-    function isRegExp(value) {
13387-      return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
13388-    }
13389-
13390-    /**
13391-     * Checks if `value` is a string.
13392-     *
13393-     * @static
13394-     * @memberOf _
13395-     * @category Objects
13396-     * @param {*} value The value to check.
13397-     * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
13398-     * @example
13399-     *
13400-     * _.isString('fred');
13401-     * // => true
13402-     */
13403-    function isString(value) {
13404-      return typeof value == 'string' ||
13405-        value && typeof value == 'object' && toString.call(value) == stringClass || false;
13406-    }
13407-
13408-    /**
13409-     * Checks if `value` is `undefined`.
13410-     *
13411-     * @static
13412-     * @memberOf _
13413-     * @category Objects
13414-     * @param {*} value The value to check.
13415-     * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
13416-     * @example
13417-     *
13418-     * _.isUndefined(void 0);
13419-     * // => true
13420-     */
13421-    function isUndefined(value) {
13422-      return typeof value == 'undefined';
13423-    }
13424-
13425-    /**
13426-     * Creates an object with the same keys as `object` and values generated by
13427-     * running each own enumerable property of `object` through the callback.
13428-     * The callback is bound to `thisArg` and invoked with three arguments;
13429-     * (value, key, object).
13430-     *
13431-     * If a property name is provided for `callback` the created "_.pluck" style
13432-     * callback will return the property value of the given element.
13433-     *
13434-     * If an object is provided for `callback` the created "_.where" style callback
13435-     * will return `true` for elements that have the properties of the given object,
13436-     * else `false`.
13437-     *
13438-     * @static
13439-     * @memberOf _
13440-     * @category Objects
13441-     * @param {Object} object The object to iterate over.
13442-     * @param {Function|Object|string} [callback=identity] The function called
13443-     *  per iteration. If a property name or object is provided it will be used
13444-     *  to create a "_.pluck" or "_.where" style callback, respectively.
13445-     * @param {*} [thisArg] The `this` binding of `callback`.
13446-     * @returns {Array} Returns a new object with values of the results of each `callback` execution.
13447-     * @example
13448-     *
13449-     * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
13450-     * // => { 'a': 3, 'b': 6, 'c': 9 }
13451-     *
13452-     * var characters = {
13453-     *   'fred': { 'name': 'fred', 'age': 40 },
13454-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
13455-     * };
13456-     *
13457-     * // using "_.pluck" callback shorthand
13458-     * _.mapValues(characters, 'age');
13459-     * // => { 'fred': 40, 'pebbles': 1 }
13460-     */
13461-    function mapValues(object, callback, thisArg) {
13462-      var result = {};
13463-      callback = lodash.createCallback(callback, thisArg, 3);
13464-
13465-      forOwn(object, function(value, key, object) {
13466-        result[key] = callback(value, key, object);
13467-      });
13468-      return result;
13469-    }
13470-
13471-    /**
13472-     * Recursively merges own enumerable properties of the source object(s), that
13473-     * don't resolve to `undefined` into the destination object. Subsequent sources
13474-     * will overwrite property assignments of previous sources. If a callback is
13475-     * provided it will be executed to produce the merged values of the destination
13476-     * and source properties. If the callback returns `undefined` merging will
13477-     * be handled by the method instead. The callback is bound to `thisArg` and
13478-     * invoked with two arguments; (objectValue, sourceValue).
13479-     *
13480-     * @static
13481-     * @memberOf _
13482-     * @category Objects
13483-     * @param {Object} object The destination object.
13484-     * @param {...Object} [source] The source objects.
13485-     * @param {Function} [callback] The function to customize merging properties.
13486-     * @param {*} [thisArg] The `this` binding of `callback`.
13487-     * @returns {Object} Returns the destination object.
13488-     * @example
13489-     *
13490-     * var names = {
13491-     *   'characters': [
13492-     *     { 'name': 'barney' },
13493-     *     { 'name': 'fred' }
13494-     *   ]
13495-     * };
13496-     *
13497-     * var ages = {
13498-     *   'characters': [
13499-     *     { 'age': 36 },
13500-     *     { 'age': 40 }
13501-     *   ]
13502-     * };
13503-     *
13504-     * _.merge(names, ages);
13505-     * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
13506-     *
13507-     * var food = {
13508-     *   'fruits': ['apple'],
13509-     *   'vegetables': ['beet']
13510-     * };
13511-     *
13512-     * var otherFood = {
13513-     *   'fruits': ['banana'],
13514-     *   'vegetables': ['carrot']
13515-     * };
13516-     *
13517-     * _.merge(food, otherFood, function(a, b) {
13518-     *   return _.isArray(a) ? a.concat(b) : undefined;
13519-     * });
13520-     * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
13521-     */
13522-    function merge(object) {
13523-      var args = arguments,
13524-        length = 2;
13525-
13526-      if (!isObject(object)) {
13527-        return object;
13528-      }
13529-      // allows working with `_.reduce` and `_.reduceRight` without using
13530-      // their `index` and `collection` arguments
13531-      if (typeof args[2] != 'number') {
13532-        length = args.length;
13533-      }
13534-      if (length > 3 && typeof args[length - 2] == 'function') {
13535-        var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
13536-      } else if (length > 2 && typeof args[length - 1] == 'function') {
13537-        callback = args[--length];
13538-      }
13539-      var sources = slice(arguments, 1, length),
13540-        index = -1,
13541-        stackA = getArray(),
13542-        stackB = getArray();
13543-
13544-      while (++index < length) {
13545-        baseMerge(object, sources[index], callback, stackA, stackB);
13546-      }
13547-      releaseArray(stackA);
13548-      releaseArray(stackB);
13549-      return object;
13550-    }
13551-
13552-    /**
13553-     * Creates a shallow clone of `object` excluding the specified properties.
13554-     * Property names may be specified as individual arguments or as arrays of
13555-     * property names. If a callback is provided it will be executed for each
13556-     * property of `object` omitting the properties the callback returns truey
13557-     * for. The callback is bound to `thisArg` and invoked with three arguments;
13558-     * (value, key, object).
13559-     *
13560-     * @static
13561-     * @memberOf _
13562-     * @category Objects
13563-     * @param {Object} object The source object.
13564-     * @param {Function|...string|string[]} [callback] The properties to omit or the
13565-     *  function called per iteration.
13566-     * @param {*} [thisArg] The `this` binding of `callback`.
13567-     * @returns {Object} Returns an object without the omitted properties.
13568-     * @example
13569-     *
13570-     * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
13571-     * // => { 'name': 'fred' }
13572-     *
13573-     * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
13574-     *   return typeof value == 'number';
13575-     * });
13576-     * // => { 'name': 'fred' }
13577-     */
13578-    function omit(object, callback, thisArg) {
13579-      var result = {};
13580-      if (typeof callback != 'function') {
13581-        var props = [];
13582-        forIn(object, function(value, key) {
13583-          props.push(key);
13584-        });
13585-        props = baseDifference(props, baseFlatten(arguments, true, false, 1));
13586-
13587-        var index = -1,
13588-          length = props.length;
13589-
13590-        while (++index < length) {
13591-          var key = props[index];
13592-          result[key] = object[key];
13593-        }
13594-      } else {
13595-        callback = lodash.createCallback(callback, thisArg, 3);
13596-        forIn(object, function(value, key, object) {
13597-          if (!callback(value, key, object)) {
13598-            result[key] = value;
13599-          }
13600-        });
13601-      }
13602-      return result;
13603-    }
13604-
13605-    /**
13606-     * Creates a two dimensional array of an object's key-value pairs,
13607-     * i.e. `[[key1, value1], [key2, value2]]`.
13608-     *
13609-     * @static
13610-     * @memberOf _
13611-     * @category Objects
13612-     * @param {Object} object The object to inspect.
13613-     * @returns {Array} Returns new array of key-value pairs.
13614-     * @example
13615-     *
13616-     * _.pairs({ 'barney': 36, 'fred': 40 });
13617-     * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
13618-     */
13619-    function pairs(object) {
13620-      var index = -1,
13621-        props = keys(object),
13622-        length = props.length,
13623-        result = Array(length);
13624-
13625-      while (++index < length) {
13626-        var key = props[index];
13627-        result[index] = [key, object[key]];
13628-      }
13629-      return result;
13630-    }
13631-
13632-    /**
13633-     * Creates a shallow clone of `object` composed of the specified properties.
13634-     * Property names may be specified as individual arguments or as arrays of
13635-     * property names. If a callback is provided it will be executed for each
13636-     * property of `object` picking the properties the callback returns truey
13637-     * for. The callback is bound to `thisArg` and invoked with three arguments;
13638-     * (value, key, object).
13639-     *
13640-     * @static
13641-     * @memberOf _
13642-     * @category Objects
13643-     * @param {Object} object The source object.
13644-     * @param {Function|...string|string[]} [callback] The function called per
13645-     *  iteration or property names to pick, specified as individual property
13646-     *  names or arrays of property names.
13647-     * @param {*} [thisArg] The `this` binding of `callback`.
13648-     * @returns {Object} Returns an object composed of the picked properties.
13649-     * @example
13650-     *
13651-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
13652-     * // => { 'name': 'fred' }
13653-     *
13654-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
13655-     *   return key.charAt(0) != '_';
13656-     * });
13657-     * // => { 'name': 'fred' }
13658-     */
13659-    function pick(object, callback, thisArg) {
13660-      var result = {};
13661-      if (typeof callback != 'function') {
13662-        var index = -1,
13663-          props = baseFlatten(arguments, true, false, 1),
13664-          length = isObject(object) ? props.length : 0;
13665-
13666-        while (++index < length) {
13667-          var key = props[index];
13668-          if (key in object) {
13669-            result[key] = object[key];
13670-          }
13671-        }
13672-      } else {
13673-        callback = lodash.createCallback(callback, thisArg, 3);
13674-        forIn(object, function(value, key, object) {
13675-          if (callback(value, key, object)) {
13676-            result[key] = value;
13677-          }
13678-        });
13679-      }
13680-      return result;
13681-    }
13682-
13683-    /**
13684-     * An alternative to `_.reduce` this method transforms `object` to a new
13685-     * `accumulator` object which is the result of running each of its own
13686-     * enumerable properties through a callback, with each callback execution
13687-     * potentially mutating the `accumulator` object. The callback is bound to
13688-     * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
13689-     * Callbacks may exit iteration early by explicitly returning `false`.
13690-     *
13691-     * @static
13692-     * @memberOf _
13693-     * @category Objects
13694-     * @param {Array|Object} object The object to iterate over.
13695-     * @param {Function} [callback=identity] The function called per iteration.
13696-     * @param {*} [accumulator] The custom accumulator value.
13697-     * @param {*} [thisArg] The `this` binding of `callback`.
13698-     * @returns {*} Returns the accumulated value.
13699-     * @example
13700-     *
13701-     * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
13702-     *   num *= num;
13703-     *   if (num % 2) {
13704-     *     return result.push(num) < 3;
13705-     *   }
13706-     * });
13707-     * // => [1, 9, 25]
13708-     *
13709-     * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
13710-     *   result[key] = num * 3;
13711-     * });
13712-     * // => { 'a': 3, 'b': 6, 'c': 9 }
13713-     */
13714-    function transform(object, callback, accumulator, thisArg) {
13715-      var isArr = isArray(object);
13716-      if (accumulator == null) {
13717-        if (isArr) {
13718-          accumulator = [];
13719-        } else {
13720-          var ctor = object && object.constructor,
13721-            proto = ctor && ctor.prototype;
13722-
13723-          accumulator = baseCreate(proto);
13724-        }
13725-      }
13726-      if (callback) {
13727-        callback = lodash.createCallback(callback, thisArg, 4);
13728-        (isArr ? forEach : forOwn)(object, function(value, index, object) {
13729-          return callback(accumulator, value, index, object);
13730-        });
13731-      }
13732-      return accumulator;
13733-    }
13734-
13735-    /**
13736-     * Creates an array composed of the own enumerable property values of `object`.
13737-     *
13738-     * @static
13739-     * @memberOf _
13740-     * @category Objects
13741-     * @param {Object} object The object to inspect.
13742-     * @returns {Array} Returns an array of property values.
13743-     * @example
13744-     *
13745-     * _.values({ 'one': 1, 'two': 2, 'three': 3 });
13746-     * // => [1, 2, 3] (property order is not guaranteed across environments)
13747-     */
13748-    function values(object) {
13749-      var index = -1,
13750-        props = keys(object),
13751-        length = props.length,
13752-        result = Array(length);
13753-
13754-      while (++index < length) {
13755-        result[index] = object[props[index]];
13756-      }
13757-      return result;
13758-    }
13759-
13760-    /*--------------------------------------------------------------------------*/
13761-
13762-    /**
13763-     * Creates an array of elements from the specified indexes, or keys, of the
13764-     * `collection`. Indexes may be specified as individual arguments or as arrays
13765-     * of indexes.
13766-     *
13767-     * @static
13768-     * @memberOf _
13769-     * @category Collections
13770-     * @param {Array|Object|string} collection The collection to iterate over.
13771-     * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
13772-     *   to retrieve, specified as individual indexes or arrays of indexes.
13773-     * @returns {Array} Returns a new array of elements corresponding to the
13774-     *  provided indexes.
13775-     * @example
13776-     *
13777-     * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
13778-     * // => ['a', 'c', 'e']
13779-     *
13780-     * _.at(['fred', 'barney', 'pebbles'], 0, 2);
13781-     * // => ['fred', 'pebbles']
13782-     */
13783-    function at(collection) {
13784-      var args = arguments,
13785-        index = -1,
13786-        props = baseFlatten(args, true, false, 1),
13787-        length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
13788-        result = Array(length);
13789-
13790-      while(++index < length) {
13791-        result[index] = collection[props[index]];
13792-      }
13793-      return result;
13794-    }
13795-
13796-    /**
13797-     * Checks if a given value is present in a collection using strict equality
13798-     * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
13799-     * offset from the end of the collection.
13800-     *
13801-     * @static
13802-     * @memberOf _
13803-     * @alias include
13804-     * @category Collections
13805-     * @param {Array|Object|string} collection The collection to iterate over.
13806-     * @param {*} target The value to check for.
13807-     * @param {number} [fromIndex=0] The index to search from.
13808-     * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
13809-     * @example
13810-     *
13811-     * _.contains([1, 2, 3], 1);
13812-     * // => true
13813-     *
13814-     * _.contains([1, 2, 3], 1, 2);
13815-     * // => false
13816-     *
13817-     * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
13818-     * // => true
13819-     *
13820-     * _.contains('pebbles', 'eb');
13821-     * // => true
13822-     */
13823-    function contains(collection, target, fromIndex) {
13824-      var index = -1,
13825-        indexOf = getIndexOf(),
13826-        length = collection ? collection.length : 0,
13827-        result = false;
13828-
13829-      fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
13830-      if (isArray(collection)) {
13831-        result = indexOf(collection, target, fromIndex) > -1;
13832-      } else if (typeof length == 'number') {
13833-        result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
13834-      } else {
13835-        forOwn(collection, function(value) {
13836-          if (++index >= fromIndex) {
13837-            return !(result = value === target);
13838-          }
13839-        });
13840-      }
13841-      return result;
13842-    }
13843-
13844-    /**
13845-     * Creates an object composed of keys generated from the results of running
13846-     * each element of `collection` through the callback. The corresponding value
13847-     * of each key is the number of times the key was returned by the callback.
13848-     * The callback is bound to `thisArg` and invoked with three arguments;
13849-     * (value, index|key, collection).
13850-     *
13851-     * If a property name is provided for `callback` the created "_.pluck" style
13852-     * callback will return the property value of the given element.
13853-     *
13854-     * If an object is provided for `callback` the created "_.where" style callback
13855-     * will return `true` for elements that have the properties of the given object,
13856-     * else `false`.
13857-     *
13858-     * @static
13859-     * @memberOf _
13860-     * @category Collections
13861-     * @param {Array|Object|string} collection The collection to iterate over.
13862-     * @param {Function|Object|string} [callback=identity] The function called
13863-     *  per iteration. If a property name or object is provided it will be used
13864-     *  to create a "_.pluck" or "_.where" style callback, respectively.
13865-     * @param {*} [thisArg] The `this` binding of `callback`.
13866-     * @returns {Object} Returns the composed aggregate object.
13867-     * @example
13868-     *
13869-     * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
13870-     * // => { '4': 1, '6': 2 }
13871-     *
13872-     * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
13873-     * // => { '4': 1, '6': 2 }
13874-     *
13875-     * _.countBy(['one', 'two', 'three'], 'length');
13876-     * // => { '3': 2, '5': 1 }
13877-     */
13878-    var countBy = createAggregator(function(result, value, key) {
13879-      (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
13880-    });
13881-
13882-    /**
13883-     * Checks if the given callback returns truey value for **all** elements of
13884-     * a collection. The callback is bound to `thisArg` and invoked with three
13885-     * arguments; (value, index|key, collection).
13886-     *
13887-     * If a property name is provided for `callback` the created "_.pluck" style
13888-     * callback will return the property value of the given element.
13889-     *
13890-     * If an object is provided for `callback` the created "_.where" style callback
13891-     * will return `true` for elements that have the properties of the given object,
13892-     * else `false`.
13893-     *
13894-     * @static
13895-     * @memberOf _
13896-     * @alias all
13897-     * @category Collections
13898-     * @param {Array|Object|string} collection The collection to iterate over.
13899-     * @param {Function|Object|string} [callback=identity] The function called
13900-     *  per iteration. If a property name or object is provided it will be used
13901-     *  to create a "_.pluck" or "_.where" style callback, respectively.
13902-     * @param {*} [thisArg] The `this` binding of `callback`.
13903-     * @returns {boolean} Returns `true` if all elements passed the callback check,
13904-     *  else `false`.
13905-     * @example
13906-     *
13907-     * _.every([true, 1, null, 'yes']);
13908-     * // => false
13909-     *
13910-     * var characters = [
13911-     *   { 'name': 'barney', 'age': 36 },
13912-     *   { 'name': 'fred',   'age': 40 }
13913-     * ];
13914-     *
13915-     * // using "_.pluck" callback shorthand
13916-     * _.every(characters, 'age');
13917-     * // => true
13918-     *
13919-     * // using "_.where" callback shorthand
13920-     * _.every(characters, { 'age': 36 });
13921-     * // => false
13922-     */
13923-    function every(collection, callback, thisArg) {
13924-      var result = true;
13925-      callback = lodash.createCallback(callback, thisArg, 3);
13926-
13927-      var index = -1,
13928-        length = collection ? collection.length : 0;
13929-
13930-      if (typeof length == 'number') {
13931-        while (++index < length) {
13932-          if (!(result = !!callback(collection[index], index, collection))) {
13933-            break;
13934-          }
13935-        }
13936-      } else {
13937-        forOwn(collection, function(value, index, collection) {
13938-          return (result = !!callback(value, index, collection));
13939-        });
13940-      }
13941-      return result;
13942-    }
13943-
13944-    /**
13945-     * Iterates over elements of a collection, returning an array of all elements
13946-     * the callback returns truey for. The callback is bound to `thisArg` and
13947-     * invoked with three arguments; (value, index|key, collection).
13948-     *
13949-     * If a property name is provided for `callback` the created "_.pluck" style
13950-     * callback will return the property value of the given element.
13951-     *
13952-     * If an object is provided for `callback` the created "_.where" style callback
13953-     * will return `true` for elements that have the properties of the given object,
13954-     * else `false`.
13955-     *
13956-     * @static
13957-     * @memberOf _
13958-     * @alias select
13959-     * @category Collections
13960-     * @param {Array|Object|string} collection The collection to iterate over.
13961-     * @param {Function|Object|string} [callback=identity] The function called
13962-     *  per iteration. If a property name or object is provided it will be used
13963-     *  to create a "_.pluck" or "_.where" style callback, respectively.
13964-     * @param {*} [thisArg] The `this` binding of `callback`.
13965-     * @returns {Array} Returns a new array of elements that passed the callback check.
13966-     * @example
13967-     *
13968-     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
13969-     * // => [2, 4, 6]
13970-     *
13971-     * var characters = [
13972-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
13973-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
13974-     * ];
13975-     *
13976-     * // using "_.pluck" callback shorthand
13977-     * _.filter(characters, 'blocked');
13978-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
13979-     *
13980-     * // using "_.where" callback shorthand
13981-     * _.filter(characters, { 'age': 36 });
13982-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
13983-     */
13984-    function filter(collection, callback, thisArg) {
13985-      var result = [];
13986-      callback = lodash.createCallback(callback, thisArg, 3);
13987-
13988-      var index = -1,
13989-        length = collection ? collection.length : 0;
13990-
13991-      if (typeof length == 'number') {
13992-        while (++index < length) {
13993-          var value = collection[index];
13994-          if (callback(value, index, collection)) {
13995-            result.push(value);
13996-          }
13997-        }
13998-      } else {
13999-        forOwn(collection, function(value, index, collection) {
14000-          if (callback(value, index, collection)) {
14001-            result.push(value);
14002-          }
14003-        });
14004-      }
14005-      return result;
14006-    }
14007-
14008-    /**
14009-     * Iterates over elements of a collection, returning the first element that
14010-     * the callback returns truey for. The callback is bound to `thisArg` and
14011-     * invoked with three arguments; (value, index|key, collection).
14012-     *
14013-     * If a property name is provided for `callback` the created "_.pluck" style
14014-     * callback will return the property value of the given element.
14015-     *
14016-     * If an object is provided for `callback` the created "_.where" style callback
14017-     * will return `true` for elements that have the properties of the given object,
14018-     * else `false`.
14019-     *
14020-     * @static
14021-     * @memberOf _
14022-     * @alias detect, findWhere
14023-     * @category Collections
14024-     * @param {Array|Object|string} collection The collection to iterate over.
14025-     * @param {Function|Object|string} [callback=identity] The function called
14026-     *  per iteration. If a property name or object is provided it will be used
14027-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14028-     * @param {*} [thisArg] The `this` binding of `callback`.
14029-     * @returns {*} Returns the found element, else `undefined`.
14030-     * @example
14031-     *
14032-     * var characters = [
14033-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
14034-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
14035-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
14036-     * ];
14037-     *
14038-     * _.find(characters, function(chr) {
14039-     *   return chr.age < 40;
14040-     * });
14041-     * // => { 'name': 'barney', 'age': 36, 'blocked': false }
14042-     *
14043-     * // using "_.where" callback shorthand
14044-     * _.find(characters, { 'age': 1 });
14045-     * // =>  { 'name': 'pebbles', 'age': 1, 'blocked': false }
14046-     *
14047-     * // using "_.pluck" callback shorthand
14048-     * _.find(characters, 'blocked');
14049-     * // => { 'name': 'fred', 'age': 40, 'blocked': true }
14050-     */
14051-    function find(collection, callback, thisArg) {
14052-      callback = lodash.createCallback(callback, thisArg, 3);
14053-
14054-      var index = -1,
14055-        length = collection ? collection.length : 0;
14056-
14057-      if (typeof length == 'number') {
14058-        while (++index < length) {
14059-          var value = collection[index];
14060-          if (callback(value, index, collection)) {
14061-            return value;
14062-          }
14063-        }
14064-      } else {
14065-        var result;
14066-        forOwn(collection, function(value, index, collection) {
14067-          if (callback(value, index, collection)) {
14068-            result = value;
14069-            return false;
14070-          }
14071-        });
14072-        return result;
14073-      }
14074-    }
14075-
14076-    /**
14077-     * This method is like `_.find` except that it iterates over elements
14078-     * of a `collection` from right to left.
14079-     *
14080-     * @static
14081-     * @memberOf _
14082-     * @category Collections
14083-     * @param {Array|Object|string} collection The collection to iterate over.
14084-     * @param {Function|Object|string} [callback=identity] The function called
14085-     *  per iteration. If a property name or object is provided it will be used
14086-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14087-     * @param {*} [thisArg] The `this` binding of `callback`.
14088-     * @returns {*} Returns the found element, else `undefined`.
14089-     * @example
14090-     *
14091-     * _.findLast([1, 2, 3, 4], function(num) {
14092-     *   return num % 2 == 1;
14093-     * });
14094-     * // => 3
14095-     */
14096-    function findLast(collection, callback, thisArg) {
14097-      var result;
14098-      callback = lodash.createCallback(callback, thisArg, 3);
14099-      forEachRight(collection, function(value, index, collection) {
14100-        if (callback(value, index, collection)) {
14101-          result = value;
14102-          return false;
14103-        }
14104-      });
14105-      return result;
14106-    }
14107-
14108-    /**
14109-     * Iterates over elements of a collection, executing the callback for each
14110-     * element. The callback is bound to `thisArg` and invoked with three arguments;
14111-     * (value, index|key, collection). Callbacks may exit iteration early by
14112-     * explicitly returning `false`.
14113-     *
14114-     * Note: As with other "Collections" methods, objects with a `length` property
14115-     * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
14116-     * may be used for object iteration.
14117-     *
14118-     * @static
14119-     * @memberOf _
14120-     * @alias each
14121-     * @category Collections
14122-     * @param {Array|Object|string} collection The collection to iterate over.
14123-     * @param {Function} [callback=identity] The function called per iteration.
14124-     * @param {*} [thisArg] The `this` binding of `callback`.
14125-     * @returns {Array|Object|string} Returns `collection`.
14126-     * @example
14127-     *
14128-     * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
14129-     * // => logs each number and returns '1,2,3'
14130-     *
14131-     * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
14132-     * // => logs each number and returns the object (property order is not guaranteed across environments)
14133-     */
14134-    function forEach(collection, callback, thisArg) {
14135-      var index = -1,
14136-        length = collection ? collection.length : 0;
14137-
14138-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
14139-      if (typeof length == 'number') {
14140-        while (++index < length) {
14141-          if (callback(collection[index], index, collection) === false) {
14142-            break;
14143-          }
14144-        }
14145-      } else {
14146-        forOwn(collection, callback);
14147-      }
14148-      return collection;
14149-    }
14150-
14151-    /**
14152-     * This method is like `_.forEach` except that it iterates over elements
14153-     * of a `collection` from right to left.
14154-     *
14155-     * @static
14156-     * @memberOf _
14157-     * @alias eachRight
14158-     * @category Collections
14159-     * @param {Array|Object|string} collection The collection to iterate over.
14160-     * @param {Function} [callback=identity] The function called per iteration.
14161-     * @param {*} [thisArg] The `this` binding of `callback`.
14162-     * @returns {Array|Object|string} Returns `collection`.
14163-     * @example
14164-     *
14165-     * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
14166-     * // => logs each number from right to left and returns '3,2,1'
14167-     */
14168-    function forEachRight(collection, callback, thisArg) {
14169-      var length = collection ? collection.length : 0;
14170-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
14171-      if (typeof length == 'number') {
14172-        while (length--) {
14173-          if (callback(collection[length], length, collection) === false) {
14174-            break;
14175-          }
14176-        }
14177-      } else {
14178-        var props = keys(collection);
14179-        length = props.length;
14180-        forOwn(collection, function(value, key, collection) {
14181-          key = props ? props[--length] : --length;
14182-          return callback(collection[key], key, collection);
14183-        });
14184-      }
14185-      return collection;
14186-    }
14187-
14188-    /**
14189-     * Creates an object composed of keys generated from the results of running
14190-     * each element of a collection through the callback. The corresponding value
14191-     * of each key is an array of the elements responsible for generating the key.
14192-     * The callback is bound to `thisArg` and invoked with three arguments;
14193-     * (value, index|key, collection).
14194-     *
14195-     * If a property name is provided for `callback` the created "_.pluck" style
14196-     * callback will return the property value of the given element.
14197-     *
14198-     * If an object is provided for `callback` the created "_.where" style callback
14199-     * will return `true` for elements that have the properties of the given object,
14200-     * else `false`
14201-     *
14202-     * @static
14203-     * @memberOf _
14204-     * @category Collections
14205-     * @param {Array|Object|string} collection The collection to iterate over.
14206-     * @param {Function|Object|string} [callback=identity] The function called
14207-     *  per iteration. If a property name or object is provided it will be used
14208-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14209-     * @param {*} [thisArg] The `this` binding of `callback`.
14210-     * @returns {Object} Returns the composed aggregate object.
14211-     * @example
14212-     *
14213-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
14214-     * // => { '4': [4.2], '6': [6.1, 6.4] }
14215-     *
14216-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
14217-     * // => { '4': [4.2], '6': [6.1, 6.4] }
14218-     *
14219-     * // using "_.pluck" callback shorthand
14220-     * _.groupBy(['one', 'two', 'three'], 'length');
14221-     * // => { '3': ['one', 'two'], '5': ['three'] }
14222-     */
14223-    var groupBy = createAggregator(function(result, value, key) {
14224-      (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
14225-    });
14226-
14227-    /**
14228-     * Creates an object composed of keys generated from the results of running
14229-     * each element of the collection through the given callback. The corresponding
14230-     * value of each key is the last element responsible for generating the key.
14231-     * The callback is bound to `thisArg` and invoked with three arguments;
14232-     * (value, index|key, collection).
14233-     *
14234-     * If a property name is provided for `callback` the created "_.pluck" style
14235-     * callback will return the property value of the given element.
14236-     *
14237-     * If an object is provided for `callback` the created "_.where" style callback
14238-     * will return `true` for elements that have the properties of the given object,
14239-     * else `false`.
14240-     *
14241-     * @static
14242-     * @memberOf _
14243-     * @category Collections
14244-     * @param {Array|Object|string} collection The collection to iterate over.
14245-     * @param {Function|Object|string} [callback=identity] The function called
14246-     *  per iteration. If a property name or object is provided it will be used
14247-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14248-     * @param {*} [thisArg] The `this` binding of `callback`.
14249-     * @returns {Object} Returns the composed aggregate object.
14250-     * @example
14251-     *
14252-     * var keys = [
14253-     *   { 'dir': 'left', 'code': 97 },
14254-     *   { 'dir': 'right', 'code': 100 }
14255-     * ];
14256-     *
14257-     * _.indexBy(keys, 'dir');
14258-     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
14259-     *
14260-     * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
14261-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
14262-     *
14263-     * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
14264-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
14265-     */
14266-    var indexBy = createAggregator(function(result, value, key) {
14267-      result[key] = value;
14268-    });
14269-
14270-    /**
14271-     * Invokes the method named by `methodName` on each element in the `collection`
14272-     * returning an array of the results of each invoked method. Additional arguments
14273-     * will be provided to each invoked method. If `methodName` is a function it
14274-     * will be invoked for, and `this` bound to, each element in the `collection`.
14275-     *
14276-     * @static
14277-     * @memberOf _
14278-     * @category Collections
14279-     * @param {Array|Object|string} collection The collection to iterate over.
14280-     * @param {Function|string} methodName The name of the method to invoke or
14281-     *  the function invoked per iteration.
14282-     * @param {...*} [arg] Arguments to invoke the method with.
14283-     * @returns {Array} Returns a new array of the results of each invoked method.
14284-     * @example
14285-     *
14286-     * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
14287-     * // => [[1, 5, 7], [1, 2, 3]]
14288-     *
14289-     * _.invoke([123, 456], String.prototype.split, '');
14290-     * // => [['1', '2', '3'], ['4', '5', '6']]
14291-     */
14292-    function invoke(collection, methodName) {
14293-      var args = slice(arguments, 2),
14294-        index = -1,
14295-        isFunc = typeof methodName == 'function',
14296-        length = collection ? collection.length : 0,
14297-        result = Array(typeof length == 'number' ? length : 0);
14298-
14299-      forEach(collection, function(value) {
14300-        result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
14301-      });
14302-      return result;
14303-    }
14304-
14305-    /**
14306-     * Creates an array of values by running each element in the collection
14307-     * through the callback. The callback is bound to `thisArg` and invoked with
14308-     * three arguments; (value, index|key, collection).
14309-     *
14310-     * If a property name is provided for `callback` the created "_.pluck" style
14311-     * callback will return the property value of the given element.
14312-     *
14313-     * If an object is provided for `callback` the created "_.where" style callback
14314-     * will return `true` for elements that have the properties of the given object,
14315-     * else `false`.
14316-     *
14317-     * @static
14318-     * @memberOf _
14319-     * @alias collect
14320-     * @category Collections
14321-     * @param {Array|Object|string} collection The collection to iterate over.
14322-     * @param {Function|Object|string} [callback=identity] The function called
14323-     *  per iteration. If a property name or object is provided it will be used
14324-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14325-     * @param {*} [thisArg] The `this` binding of `callback`.
14326-     * @returns {Array} Returns a new array of the results of each `callback` execution.
14327-     * @example
14328-     *
14329-     * _.map([1, 2, 3], function(num) { return num * 3; });
14330-     * // => [3, 6, 9]
14331-     *
14332-     * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
14333-     * // => [3, 6, 9] (property order is not guaranteed across environments)
14334-     *
14335-     * var characters = [
14336-     *   { 'name': 'barney', 'age': 36 },
14337-     *   { 'name': 'fred',   'age': 40 }
14338-     * ];
14339-     *
14340-     * // using "_.pluck" callback shorthand
14341-     * _.map(characters, 'name');
14342-     * // => ['barney', 'fred']
14343-     */
14344-    function map(collection, callback, thisArg) {
14345-      var index = -1,
14346-        length = collection ? collection.length : 0;
14347-
14348-      callback = lodash.createCallback(callback, thisArg, 3);
14349-      if (typeof length == 'number') {
14350-        var result = Array(length);
14351-        while (++index < length) {
14352-          result[index] = callback(collection[index], index, collection);
14353-        }
14354-      } else {
14355-        result = [];
14356-        forOwn(collection, function(value, key, collection) {
14357-          result[++index] = callback(value, key, collection);
14358-        });
14359-      }
14360-      return result;
14361-    }
14362-
14363-    /**
14364-     * Retrieves the maximum value of a collection. If the collection is empty or
14365-     * falsey `-Infinity` is returned. If a callback is provided it will be executed
14366-     * for each value in the collection to generate the criterion by which the value
14367-     * is ranked. The callback is bound to `thisArg` and invoked with three
14368-     * arguments; (value, index, collection).
14369-     *
14370-     * If a property name is provided for `callback` the created "_.pluck" style
14371-     * callback will return the property value of the given element.
14372-     *
14373-     * If an object is provided for `callback` the created "_.where" style callback
14374-     * will return `true` for elements that have the properties of the given object,
14375-     * else `false`.
14376-     *
14377-     * @static
14378-     * @memberOf _
14379-     * @category Collections
14380-     * @param {Array|Object|string} collection The collection to iterate over.
14381-     * @param {Function|Object|string} [callback=identity] The function called
14382-     *  per iteration. If a property name or object is provided it will be used
14383-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14384-     * @param {*} [thisArg] The `this` binding of `callback`.
14385-     * @returns {*} Returns the maximum value.
14386-     * @example
14387-     *
14388-     * _.max([4, 2, 8, 6]);
14389-     * // => 8
14390-     *
14391-     * var characters = [
14392-     *   { 'name': 'barney', 'age': 36 },
14393-     *   { 'name': 'fred',   'age': 40 }
14394-     * ];
14395-     *
14396-     * _.max(characters, function(chr) { return chr.age; });
14397-     * // => { 'name': 'fred', 'age': 40 };
14398-     *
14399-     * // using "_.pluck" callback shorthand
14400-     * _.max(characters, 'age');
14401-     * // => { 'name': 'fred', 'age': 40 };
14402-     */
14403-    function max(collection, callback, thisArg) {
14404-      var computed = -Infinity,
14405-        result = computed;
14406-
14407-      // allows working with functions like `_.map` without using
14408-      // their `index` argument as a callback
14409-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
14410-        callback = null;
14411-      }
14412-      if (callback == null && isArray(collection)) {
14413-        var index = -1,
14414-          length = collection.length;
14415-
14416-        while (++index < length) {
14417-          var value = collection[index];
14418-          if (value > result) {
14419-            result = value;
14420-          }
14421-        }
14422-      } else {
14423-        callback = (callback == null && isString(collection))
14424-          ? charAtCallback
14425-          : lodash.createCallback(callback, thisArg, 3);
14426-
14427-        forEach(collection, function(value, index, collection) {
14428-          var current = callback(value, index, collection);
14429-          if (current > computed) {
14430-            computed = current;
14431-            result = value;
14432-          }
14433-        });
14434-      }
14435-      return result;
14436-    }
14437-
14438-    /**
14439-     * Retrieves the minimum value of a collection. If the collection is empty or
14440-     * falsey `Infinity` is returned. If a callback is provided it will be executed
14441-     * for each value in the collection to generate the criterion by which the value
14442-     * is ranked. The callback is bound to `thisArg` and invoked with three
14443-     * arguments; (value, index, collection).
14444-     *
14445-     * If a property name is provided for `callback` the created "_.pluck" style
14446-     * callback will return the property value of the given element.
14447-     *
14448-     * If an object is provided for `callback` the created "_.where" style callback
14449-     * will return `true` for elements that have the properties of the given object,
14450-     * else `false`.
14451-     *
14452-     * @static
14453-     * @memberOf _
14454-     * @category Collections
14455-     * @param {Array|Object|string} collection The collection to iterate over.
14456-     * @param {Function|Object|string} [callback=identity] The function called
14457-     *  per iteration. If a property name or object is provided it will be used
14458-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14459-     * @param {*} [thisArg] The `this` binding of `callback`.
14460-     * @returns {*} Returns the minimum value.
14461-     * @example
14462-     *
14463-     * _.min([4, 2, 8, 6]);
14464-     * // => 2
14465-     *
14466-     * var characters = [
14467-     *   { 'name': 'barney', 'age': 36 },
14468-     *   { 'name': 'fred',   'age': 40 }
14469-     * ];
14470-     *
14471-     * _.min(characters, function(chr) { return chr.age; });
14472-     * // => { 'name': 'barney', 'age': 36 };
14473-     *
14474-     * // using "_.pluck" callback shorthand
14475-     * _.min(characters, 'age');
14476-     * // => { 'name': 'barney', 'age': 36 };
14477-     */
14478-    function min(collection, callback, thisArg) {
14479-      var computed = Infinity,
14480-        result = computed;
14481-
14482-      // allows working with functions like `_.map` without using
14483-      // their `index` argument as a callback
14484-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
14485-        callback = null;
14486-      }
14487-      if (callback == null && isArray(collection)) {
14488-        var index = -1,
14489-          length = collection.length;
14490-
14491-        while (++index < length) {
14492-          var value = collection[index];
14493-          if (value < result) {
14494-            result = value;
14495-          }
14496-        }
14497-      } else {
14498-        callback = (callback == null && isString(collection))
14499-          ? charAtCallback
14500-          : lodash.createCallback(callback, thisArg, 3);
14501-
14502-        forEach(collection, function(value, index, collection) {
14503-          var current = callback(value, index, collection);
14504-          if (current < computed) {
14505-            computed = current;
14506-            result = value;
14507-          }
14508-        });
14509-      }
14510-      return result;
14511-    }
14512-
14513-    /**
14514-     * Retrieves the value of a specified property from all elements in the collection.
14515-     *
14516-     * @static
14517-     * @memberOf _
14518-     * @type Function
14519-     * @category Collections
14520-     * @param {Array|Object|string} collection The collection to iterate over.
14521-     * @param {string} property The name of the property to pluck.
14522-     * @returns {Array} Returns a new array of property values.
14523-     * @example
14524-     *
14525-     * var characters = [
14526-     *   { 'name': 'barney', 'age': 36 },
14527-     *   { 'name': 'fred',   'age': 40 }
14528-     * ];
14529-     *
14530-     * _.pluck(characters, 'name');
14531-     * // => ['barney', 'fred']
14532-     */
14533-    var pluck = map;
14534-
14535-    /**
14536-     * Reduces a collection to a value which is the accumulated result of running
14537-     * each element in the collection through the callback, where each successive
14538-     * callback execution consumes the return value of the previous execution. If
14539-     * `accumulator` is not provided the first element of the collection will be
14540-     * used as the initial `accumulator` value. The callback is bound to `thisArg`
14541-     * and invoked with four arguments; (accumulator, value, index|key, collection).
14542-     *
14543-     * @static
14544-     * @memberOf _
14545-     * @alias foldl, inject
14546-     * @category Collections
14547-     * @param {Array|Object|string} collection The collection to iterate over.
14548-     * @param {Function} [callback=identity] The function called per iteration.
14549-     * @param {*} [accumulator] Initial value of the accumulator.
14550-     * @param {*} [thisArg] The `this` binding of `callback`.
14551-     * @returns {*} Returns the accumulated value.
14552-     * @example
14553-     *
14554-     * var sum = _.reduce([1, 2, 3], function(sum, num) {
14555-     *   return sum + num;
14556-     * });
14557-     * // => 6
14558-     *
14559-     * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
14560-     *   result[key] = num * 3;
14561-     *   return result;
14562-     * }, {});
14563-     * // => { 'a': 3, 'b': 6, 'c': 9 }
14564-     */
14565-    function reduce(collection, callback, accumulator, thisArg) {
14566-      if (!collection) return accumulator;
14567-      var noaccum = arguments.length < 3;
14568-      callback = lodash.createCallback(callback, thisArg, 4);
14569-
14570-      var index = -1,
14571-        length = collection.length;
14572-
14573-      if (typeof length == 'number') {
14574-        if (noaccum) {
14575-          accumulator = collection[++index];
14576-        }
14577-        while (++index < length) {
14578-          accumulator = callback(accumulator, collection[index], index, collection);
14579-        }
14580-      } else {
14581-        forOwn(collection, function(value, index, collection) {
14582-          accumulator = noaccum
14583-            ? (noaccum = false, value)
14584-            : callback(accumulator, value, index, collection)
14585-        });
14586-      }
14587-      return accumulator;
14588-    }
14589-
14590-    /**
14591-     * This method is like `_.reduce` except that it iterates over elements
14592-     * of a `collection` from right to left.
14593-     *
14594-     * @static
14595-     * @memberOf _
14596-     * @alias foldr
14597-     * @category Collections
14598-     * @param {Array|Object|string} collection The collection to iterate over.
14599-     * @param {Function} [callback=identity] The function called per iteration.
14600-     * @param {*} [accumulator] Initial value of the accumulator.
14601-     * @param {*} [thisArg] The `this` binding of `callback`.
14602-     * @returns {*} Returns the accumulated value.
14603-     * @example
14604-     *
14605-     * var list = [[0, 1], [2, 3], [4, 5]];
14606-     * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
14607-     * // => [4, 5, 2, 3, 0, 1]
14608-     */
14609-    function reduceRight(collection, callback, accumulator, thisArg) {
14610-      var noaccum = arguments.length < 3;
14611-      callback = lodash.createCallback(callback, thisArg, 4);
14612-      forEachRight(collection, function(value, index, collection) {
14613-        accumulator = noaccum
14614-          ? (noaccum = false, value)
14615-          : callback(accumulator, value, index, collection);
14616-      });
14617-      return accumulator;
14618-    }
14619-
14620-    /**
14621-     * The opposite of `_.filter` this method returns the elements of a
14622-     * collection that the callback does **not** return truey for.
14623-     *
14624-     * If a property name is provided for `callback` the created "_.pluck" style
14625-     * callback will return the property value of the given element.
14626-     *
14627-     * If an object is provided for `callback` the created "_.where" style callback
14628-     * will return `true` for elements that have the properties of the given object,
14629-     * else `false`.
14630-     *
14631-     * @static
14632-     * @memberOf _
14633-     * @category Collections
14634-     * @param {Array|Object|string} collection The collection to iterate over.
14635-     * @param {Function|Object|string} [callback=identity] The function called
14636-     *  per iteration. If a property name or object is provided it will be used
14637-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14638-     * @param {*} [thisArg] The `this` binding of `callback`.
14639-     * @returns {Array} Returns a new array of elements that failed the callback check.
14640-     * @example
14641-     *
14642-     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
14643-     * // => [1, 3, 5]
14644-     *
14645-     * var characters = [
14646-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
14647-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
14648-     * ];
14649-     *
14650-     * // using "_.pluck" callback shorthand
14651-     * _.reject(characters, 'blocked');
14652-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
14653-     *
14654-     * // using "_.where" callback shorthand
14655-     * _.reject(characters, { 'age': 36 });
14656-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
14657-     */
14658-    function reject(collection, callback, thisArg) {
14659-      callback = lodash.createCallback(callback, thisArg, 3);
14660-      return filter(collection, function(value, index, collection) {
14661-        return !callback(value, index, collection);
14662-      });
14663-    }
14664-
14665-    /**
14666-     * Retrieves a random element or `n` random elements from a collection.
14667-     *
14668-     * @static
14669-     * @memberOf _
14670-     * @category Collections
14671-     * @param {Array|Object|string} collection The collection to sample.
14672-     * @param {number} [n] The number of elements to sample.
14673-     * @param- {Object} [guard] Allows working with functions like `_.map`
14674-     *  without using their `index` arguments as `n`.
14675-     * @returns {Array} Returns the random sample(s) of `collection`.
14676-     * @example
14677-     *
14678-     * _.sample([1, 2, 3, 4]);
14679-     * // => 2
14680-     *
14681-     * _.sample([1, 2, 3, 4], 2);
14682-     * // => [3, 1]
14683-     */
14684-    function sample(collection, n, guard) {
14685-      if (collection && typeof collection.length != 'number') {
14686-        collection = values(collection);
14687-      }
14688-      if (n == null || guard) {
14689-        return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
14690-      }
14691-      var result = shuffle(collection);
14692-      result.length = nativeMin(nativeMax(0, n), result.length);
14693-      return result;
14694-    }
14695-
14696-    /**
14697-     * Creates an array of shuffled values, using a version of the Fisher-Yates
14698-     * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
14699-     *
14700-     * @static
14701-     * @memberOf _
14702-     * @category Collections
14703-     * @param {Array|Object|string} collection The collection to shuffle.
14704-     * @returns {Array} Returns a new shuffled collection.
14705-     * @example
14706-     *
14707-     * _.shuffle([1, 2, 3, 4, 5, 6]);
14708-     * // => [4, 1, 6, 3, 5, 2]
14709-     */
14710-    function shuffle(collection) {
14711-      var index = -1,
14712-        length = collection ? collection.length : 0,
14713-        result = Array(typeof length == 'number' ? length : 0);
14714-
14715-      forEach(collection, function(value) {
14716-        var rand = baseRandom(0, ++index);
14717-        result[index] = result[rand];
14718-        result[rand] = value;
14719-      });
14720-      return result;
14721-    }
14722-
14723-    /**
14724-     * Gets the size of the `collection` by returning `collection.length` for arrays
14725-     * and array-like objects or the number of own enumerable properties for objects.
14726-     *
14727-     * @static
14728-     * @memberOf _
14729-     * @category Collections
14730-     * @param {Array|Object|string} collection The collection to inspect.
14731-     * @returns {number} Returns `collection.length` or number of own enumerable properties.
14732-     * @example
14733-     *
14734-     * _.size([1, 2]);
14735-     * // => 2
14736-     *
14737-     * _.size({ 'one': 1, 'two': 2, 'three': 3 });
14738-     * // => 3
14739-     *
14740-     * _.size('pebbles');
14741-     * // => 7
14742-     */
14743-    function size(collection) {
14744-      var length = collection ? collection.length : 0;
14745-      return typeof length == 'number' ? length : keys(collection).length;
14746-    }
14747-
14748-    /**
14749-     * Checks if the callback returns a truey value for **any** element of a
14750-     * collection. The function returns as soon as it finds a passing value and
14751-     * does not iterate over the entire collection. The callback is bound to
14752-     * `thisArg` and invoked with three arguments; (value, index|key, collection).
14753-     *
14754-     * If a property name is provided for `callback` the created "_.pluck" style
14755-     * callback will return the property value of the given element.
14756-     *
14757-     * If an object is provided for `callback` the created "_.where" style callback
14758-     * will return `true` for elements that have the properties of the given object,
14759-     * else `false`.
14760-     *
14761-     * @static
14762-     * @memberOf _
14763-     * @alias any
14764-     * @category Collections
14765-     * @param {Array|Object|string} collection The collection to iterate over.
14766-     * @param {Function|Object|string} [callback=identity] The function called
14767-     *  per iteration. If a property name or object is provided it will be used
14768-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14769-     * @param {*} [thisArg] The `this` binding of `callback`.
14770-     * @returns {boolean} Returns `true` if any element passed the callback check,
14771-     *  else `false`.
14772-     * @example
14773-     *
14774-     * _.some([null, 0, 'yes', false], Boolean);
14775-     * // => true
14776-     *
14777-     * var characters = [
14778-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
14779-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
14780-     * ];
14781-     *
14782-     * // using "_.pluck" callback shorthand
14783-     * _.some(characters, 'blocked');
14784-     * // => true
14785-     *
14786-     * // using "_.where" callback shorthand
14787-     * _.some(characters, { 'age': 1 });
14788-     * // => false
14789-     */
14790-    function some(collection, callback, thisArg) {
14791-      var result;
14792-      callback = lodash.createCallback(callback, thisArg, 3);
14793-
14794-      var index = -1,
14795-        length = collection ? collection.length : 0;
14796-
14797-      if (typeof length == 'number') {
14798-        while (++index < length) {
14799-          if ((result = callback(collection[index], index, collection))) {
14800-            break;
14801-          }
14802-        }
14803-      } else {
14804-        forOwn(collection, function(value, index, collection) {
14805-          return !(result = callback(value, index, collection));
14806-        });
14807-      }
14808-      return !!result;
14809-    }
14810-
14811-    /**
14812-     * Creates an array of elements, sorted in ascending order by the results of
14813-     * running each element in a collection through the callback. This method
14814-     * performs a stable sort, that is, it will preserve the original sort order
14815-     * of equal elements. The callback is bound to `thisArg` and invoked with
14816-     * three arguments; (value, index|key, collection).
14817-     *
14818-     * If a property name is provided for `callback` the created "_.pluck" style
14819-     * callback will return the property value of the given element.
14820-     *
14821-     * If an array of property names is provided for `callback` the collection
14822-     * will be sorted by each property value.
14823-     *
14824-     * If an object is provided for `callback` the created "_.where" style callback
14825-     * will return `true` for elements that have the properties of the given object,
14826-     * else `false`.
14827-     *
14828-     * @static
14829-     * @memberOf _
14830-     * @category Collections
14831-     * @param {Array|Object|string} collection The collection to iterate over.
14832-     * @param {Array|Function|Object|string} [callback=identity] The function called
14833-     *  per iteration. If a property name or object is provided it will be used
14834-     *  to create a "_.pluck" or "_.where" style callback, respectively.
14835-     * @param {*} [thisArg] The `this` binding of `callback`.
14836-     * @returns {Array} Returns a new array of sorted elements.
14837-     * @example
14838-     *
14839-     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
14840-     * // => [3, 1, 2]
14841-     *
14842-     * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
14843-     * // => [3, 1, 2]
14844-     *
14845-     * var characters = [
14846-     *   { 'name': 'barney',  'age': 36 },
14847-     *   { 'name': 'fred',    'age': 40 },
14848-     *   { 'name': 'barney',  'age': 26 },
14849-     *   { 'name': 'fred',    'age': 30 }
14850-     * ];
14851-     *
14852-     * // using "_.pluck" callback shorthand
14853-     * _.map(_.sortBy(characters, 'age'), _.values);
14854-     * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
14855-     *
14856-     * // sorting by multiple properties
14857-     * _.map(_.sortBy(characters, ['name', 'age']), _.values);
14858-     * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
14859-     */
14860-    function sortBy(collection, callback, thisArg) {
14861-      var index = -1,
14862-        isArr = isArray(callback),
14863-        length = collection ? collection.length : 0,
14864-        result = Array(typeof length == 'number' ? length : 0);
14865-
14866-      if (!isArr) {
14867-        callback = lodash.createCallback(callback, thisArg, 3);
14868-      }
14869-      forEach(collection, function(value, key, collection) {
14870-        var object = result[++index] = getObject();
14871-        if (isArr) {
14872-          object.criteria = map(callback, function(key) { return value[key]; });
14873-        } else {
14874-          (object.criteria = getArray())[0] = callback(value, key, collection);
14875-        }
14876-        object.index = index;
14877-        object.value = value;
14878-      });
14879-
14880-      length = result.length;
14881-      result.sort(compareAscending);
14882-      while (length--) {
14883-        var object = result[length];
14884-        result[length] = object.value;
14885-        if (!isArr) {
14886-          releaseArray(object.criteria);
14887-        }
14888-        releaseObject(object);
14889-      }
14890-      return result;
14891-    }
14892-
14893-    /**
14894-     * Converts the `collection` to an array.
14895-     *
14896-     * @static
14897-     * @memberOf _
14898-     * @category Collections
14899-     * @param {Array|Object|string} collection The collection to convert.
14900-     * @returns {Array} Returns the new converted array.
14901-     * @example
14902-     *
14903-     * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
14904-     * // => [2, 3, 4]
14905-     */
14906-    function toArray(collection) {
14907-      if (collection && typeof collection.length == 'number') {
14908-        return slice(collection);
14909-      }
14910-      return values(collection);
14911-    }
14912-
14913-    /**
14914-     * Performs a deep comparison of each element in a `collection` to the given
14915-     * `properties` object, returning an array of all elements that have equivalent
14916-     * property values.
14917-     *
14918-     * @static
14919-     * @memberOf _
14920-     * @type Function
14921-     * @category Collections
14922-     * @param {Array|Object|string} collection The collection to iterate over.
14923-     * @param {Object} props The object of property values to filter by.
14924-     * @returns {Array} Returns a new array of elements that have the given properties.
14925-     * @example
14926-     *
14927-     * var characters = [
14928-     *   { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
14929-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
14930-     * ];
14931-     *
14932-     * _.where(characters, { 'age': 36 });
14933-     * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
14934-     *
14935-     * _.where(characters, { 'pets': ['dino'] });
14936-     * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
14937-     */
14938-    var where = filter;
14939-
14940-    /*--------------------------------------------------------------------------*/
14941-
14942-    /**
14943-     * Creates an array with all falsey values removed. The values `false`, `null`,
14944-     * `0`, `""`, `undefined`, and `NaN` are all falsey.
14945-     *
14946-     * @static
14947-     * @memberOf _
14948-     * @category Arrays
14949-     * @param {Array} array The array to compact.
14950-     * @returns {Array} Returns a new array of filtered values.
14951-     * @example
14952-     *
14953-     * _.compact([0, 1, false, 2, '', 3]);
14954-     * // => [1, 2, 3]
14955-     */
14956-    function compact(array) {
14957-      var index = -1,
14958-        length = array ? array.length : 0,
14959-        result = [];
14960-
14961-      while (++index < length) {
14962-        var value = array[index];
14963-        if (value) {
14964-          result.push(value);
14965-        }
14966-      }
14967-      return result;
14968-    }
14969-
14970-    /**
14971-     * Creates an array excluding all values of the provided arrays using strict
14972-     * equality for comparisons, i.e. `===`.
14973-     *
14974-     * @static
14975-     * @memberOf _
14976-     * @category Arrays
14977-     * @param {Array} array The array to process.
14978-     * @param {...Array} [values] The arrays of values to exclude.
14979-     * @returns {Array} Returns a new array of filtered values.
14980-     * @example
14981-     *
14982-     * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
14983-     * // => [1, 3, 4]
14984-     */
14985-    function difference(array) {
14986-      return baseDifference(array, baseFlatten(arguments, true, true, 1));
14987-    }
14988-
14989-    /**
14990-     * This method is like `_.find` except that it returns the index of the first
14991-     * element that passes the callback check, instead of the element itself.
14992-     *
14993-     * If a property name is provided for `callback` the created "_.pluck" style
14994-     * callback will return the property value of the given element.
14995-     *
14996-     * If an object is provided for `callback` the created "_.where" style callback
14997-     * will return `true` for elements that have the properties of the given object,
14998-     * else `false`.
14999-     *
15000-     * @static
15001-     * @memberOf _
15002-     * @category Arrays
15003-     * @param {Array} array The array to search.
15004-     * @param {Function|Object|string} [callback=identity] The function called
15005-     *  per iteration. If a property name or object is provided it will be used
15006-     *  to create a "_.pluck" or "_.where" style callback, respectively.
15007-     * @param {*} [thisArg] The `this` binding of `callback`.
15008-     * @returns {number} Returns the index of the found element, else `-1`.
15009-     * @example
15010-     *
15011-     * var characters = [
15012-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
15013-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
15014-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
15015-     * ];
15016-     *
15017-     * _.findIndex(characters, function(chr) {
15018-     *   return chr.age < 20;
15019-     * });
15020-     * // => 2
15021-     *
15022-     * // using "_.where" callback shorthand
15023-     * _.findIndex(characters, { 'age': 36 });
15024-     * // => 0
15025-     *
15026-     * // using "_.pluck" callback shorthand
15027-     * _.findIndex(characters, 'blocked');
15028-     * // => 1
15029-     */
15030-    function findIndex(array, callback, thisArg) {
15031-      var index = -1,
15032-        length = array ? array.length : 0;
15033-
15034-      callback = lodash.createCallback(callback, thisArg, 3);
15035-      while (++index < length) {
15036-        if (callback(array[index], index, array)) {
15037-          return index;
15038-        }
15039-      }
15040-      return -1;
15041-    }
15042-
15043-    /**
15044-     * This method is like `_.findIndex` except that it iterates over elements
15045-     * of a `collection` from right to left.
15046-     *
15047-     * If a property name is provided for `callback` the created "_.pluck" style
15048-     * callback will return the property value of the given element.
15049-     *
15050-     * If an object is provided for `callback` the created "_.where" style callback
15051-     * will return `true` for elements that have the properties of the given object,
15052-     * else `false`.
15053-     *
15054-     * @static
15055-     * @memberOf _
15056-     * @category Arrays
15057-     * @param {Array} array The array to search.
15058-     * @param {Function|Object|string} [callback=identity] The function called
15059-     *  per iteration. If a property name or object is provided it will be used
15060-     *  to create a "_.pluck" or "_.where" style callback, respectively.
15061-     * @param {*} [thisArg] The `this` binding of `callback`.
15062-     * @returns {number} Returns the index of the found element, else `-1`.
15063-     * @example
15064-     *
15065-     * var characters = [
15066-     *   { 'name': 'barney',  'age': 36, 'blocked': true },
15067-     *   { 'name': 'fred',    'age': 40, 'blocked': false },
15068-     *   { 'name': 'pebbles', 'age': 1,  'blocked': true }
15069-     * ];
15070-     *
15071-     * _.findLastIndex(characters, function(chr) {
15072-     *   return chr.age > 30;
15073-     * });
15074-     * // => 1
15075-     *
15076-     * // using "_.where" callback shorthand
15077-     * _.findLastIndex(characters, { 'age': 36 });
15078-     * // => 0
15079-     *
15080-     * // using "_.pluck" callback shorthand
15081-     * _.findLastIndex(characters, 'blocked');
15082-     * // => 2
15083-     */
15084-    function findLastIndex(array, callback, thisArg) {
15085-      var length = array ? array.length : 0;
15086-      callback = lodash.createCallback(callback, thisArg, 3);
15087-      while (length--) {
15088-        if (callback(array[length], length, array)) {
15089-          return length;
15090-        }
15091-      }
15092-      return -1;
15093-    }
15094-
15095-    /**
15096-     * Gets the first element or first `n` elements of an array. If a callback
15097-     * is provided elements at the beginning of the array are returned as long
15098-     * as the callback returns truey. The callback is bound to `thisArg` and
15099-     * invoked with three arguments; (value, index, array).
15100-     *
15101-     * If a property name is provided for `callback` the created "_.pluck" style
15102-     * callback will return the property value of the given element.
15103-     *
15104-     * If an object is provided for `callback` the created "_.where" style callback
15105-     * will return `true` for elements that have the properties of the given object,
15106-     * else `false`.
15107-     *
15108-     * @static
15109-     * @memberOf _
15110-     * @alias head, take
15111-     * @category Arrays
15112-     * @param {Array} array The array to query.
15113-     * @param {Function|Object|number|string} [callback] The function called
15114-     *  per element or the number of elements to return. If a property name or
15115-     *  object is provided it will be used to create a "_.pluck" or "_.where"
15116-     *  style callback, respectively.
15117-     * @param {*} [thisArg] The `this` binding of `callback`.
15118-     * @returns {*} Returns the first element(s) of `array`.
15119-     * @example
15120-     *
15121-     * _.first([1, 2, 3]);
15122-     * // => 1
15123-     *
15124-     * _.first([1, 2, 3], 2);
15125-     * // => [1, 2]
15126-     *
15127-     * _.first([1, 2, 3], function(num) {
15128-     *   return num < 3;
15129-     * });
15130-     * // => [1, 2]
15131-     *
15132-     * var characters = [
15133-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
15134-     *   { 'name': 'fred',    'blocked': false, 'employer': 'slate' },
15135-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
15136-     * ];
15137-     *
15138-     * // using "_.pluck" callback shorthand
15139-     * _.first(characters, 'blocked');
15140-     * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
15141-     *
15142-     * // using "_.where" callback shorthand
15143-     * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
15144-     * // => ['barney', 'fred']
15145-     */
15146-    function first(array, callback, thisArg) {
15147-      var n = 0,
15148-        length = array ? array.length : 0;
15149-
15150-      if (typeof callback != 'number' && callback != null) {
15151-        var index = -1;
15152-        callback = lodash.createCallback(callback, thisArg, 3);
15153-        while (++index < length && callback(array[index], index, array)) {
15154-          n++;
15155-        }
15156-      } else {
15157-        n = callback;
15158-        if (n == null || thisArg) {
15159-          return array ? array[0] : undefined;
15160-        }
15161-      }
15162-      return slice(array, 0, nativeMin(nativeMax(0, n), length));
15163-    }
15164-
15165-    /**
15166-     * Flattens a nested array (the nesting can be to any depth). If `isShallow`
15167-     * is truey, the array will only be flattened a single level. If a callback
15168-     * is provided each element of the array is passed through the callback before
15169-     * flattening. The callback is bound to `thisArg` and invoked with three
15170-     * arguments; (value, index, array).
15171-     *
15172-     * If a property name is provided for `callback` the created "_.pluck" style
15173-     * callback will return the property value of the given element.
15174-     *
15175-     * If an object is provided for `callback` the created "_.where" style callback
15176-     * will return `true` for elements that have the properties of the given object,
15177-     * else `false`.
15178-     *
15179-     * @static
15180-     * @memberOf _
15181-     * @category Arrays
15182-     * @param {Array} array The array to flatten.
15183-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
15184-     * @param {Function|Object|string} [callback=identity] The function called
15185-     *  per iteration. If a property name or object is provided it will be used
15186-     *  to create a "_.pluck" or "_.where" style callback, respectively.
15187-     * @param {*} [thisArg] The `this` binding of `callback`.
15188-     * @returns {Array} Returns a new flattened array.
15189-     * @example
15190-     *
15191-     * _.flatten([1, [2], [3, [[4]]]]);
15192-     * // => [1, 2, 3, 4];
15193-     *
15194-     * _.flatten([1, [2], [3, [[4]]]], true);
15195-     * // => [1, 2, 3, [[4]]];
15196-     *
15197-     * var characters = [
15198-     *   { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
15199-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
15200-     * ];
15201-     *
15202-     * // using "_.pluck" callback shorthand
15203-     * _.flatten(characters, 'pets');
15204-     * // => ['hoppy', 'baby puss', 'dino']
15205-     */
15206-    function flatten(array, isShallow, callback, thisArg) {
15207-      // juggle arguments
15208-      if (typeof isShallow != 'boolean' && isShallow != null) {
15209-        thisArg = callback;
15210-        callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
15211-        isShallow = false;
15212-      }
15213-      if (callback != null) {
15214-        array = map(array, callback, thisArg);
15215-      }
15216-      return baseFlatten(array, isShallow);
15217-    }
15218-
15219-    /**
15220-     * Gets the index at which the first occurrence of `value` is found using
15221-     * strict equality for comparisons, i.e. `===`. If the array is already sorted
15222-     * providing `true` for `fromIndex` will run a faster binary search.
15223-     *
15224-     * @static
15225-     * @memberOf _
15226-     * @category Arrays
15227-     * @param {Array} array The array to search.
15228-     * @param {*} value The value to search for.
15229-     * @param {boolean|number} [fromIndex=0] The index to search from or `true`
15230-     *  to perform a binary search on a sorted array.
15231-     * @returns {number} Returns the index of the matched value or `-1`.
15232-     * @example
15233-     *
15234-     * _.indexOf([1, 2, 3, 1, 2, 3], 2);
15235-     * // => 1
15236-     *
15237-     * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
15238-     * // => 4
15239-     *
15240-     * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
15241-     * // => 2
15242-     */
15243-    function indexOf(array, value, fromIndex) {
15244-      if (typeof fromIndex == 'number') {
15245-        var length = array ? array.length : 0;
15246-        fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
15247-      } else if (fromIndex) {
15248-        var index = sortedIndex(array, value);
15249-        return array[index] === value ? index : -1;
15250-      }
15251-      return baseIndexOf(array, value, fromIndex);
15252-    }
15253-
15254-    /**
15255-     * Gets all but the last element or last `n` elements of an array. If a
15256-     * callback is provided elements at the end of the array are excluded from
15257-     * the result as long as the callback returns truey. The callback is bound
15258-     * to `thisArg` and invoked with three arguments; (value, index, array).
15259-     *
15260-     * If a property name is provided for `callback` the created "_.pluck" style
15261-     * callback will return the property value of the given element.
15262-     *
15263-     * If an object is provided for `callback` the created "_.where" style callback
15264-     * will return `true` for elements that have the properties of the given object,
15265-     * else `false`.
15266-     *
15267-     * @static
15268-     * @memberOf _
15269-     * @category Arrays
15270-     * @param {Array} array The array to query.
15271-     * @param {Function|Object|number|string} [callback=1] The function called
15272-     *  per element or the number of elements to exclude. If a property name or
15273-     *  object is provided it will be used to create a "_.pluck" or "_.where"
15274-     *  style callback, respectively.
15275-     * @param {*} [thisArg] The `this` binding of `callback`.
15276-     * @returns {Array} Returns a slice of `array`.
15277-     * @example
15278-     *
15279-     * _.initial([1, 2, 3]);
15280-     * // => [1, 2]
15281-     *
15282-     * _.initial([1, 2, 3], 2);
15283-     * // => [1]
15284-     *
15285-     * _.initial([1, 2, 3], function(num) {
15286-     *   return num > 1;
15287-     * });
15288-     * // => [1]
15289-     *
15290-     * var characters = [
15291-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
15292-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
15293-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
15294-     * ];
15295-     *
15296-     * // using "_.pluck" callback shorthand
15297-     * _.initial(characters, 'blocked');
15298-     * // => [{ 'name': 'barney',  'blocked': false, 'employer': 'slate' }]
15299-     *
15300-     * // using "_.where" callback shorthand
15301-     * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
15302-     * // => ['barney', 'fred']
15303-     */
15304-    function initial(array, callback, thisArg) {
15305-      var n = 0,
15306-        length = array ? array.length : 0;
15307-
15308-      if (typeof callback != 'number' && callback != null) {
15309-        var index = length;
15310-        callback = lodash.createCallback(callback, thisArg, 3);
15311-        while (index-- && callback(array[index], index, array)) {
15312-          n++;
15313-        }
15314-      } else {
15315-        n = (callback == null || thisArg) ? 1 : callback || n;
15316-      }
15317-      return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
15318-    }
15319-
15320-    /**
15321-     * Creates an array of unique values present in all provided arrays using
15322-     * strict equality for comparisons, i.e. `===`.
15323-     *
15324-     * @static
15325-     * @memberOf _
15326-     * @category Arrays
15327-     * @param {...Array} [array] The arrays to inspect.
15328-     * @returns {Array} Returns an array of shared values.
15329-     * @example
15330-     *
15331-     * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
15332-     * // => [1, 2]
15333-     */
15334-    function intersection() {
15335-      var args = [],
15336-        argsIndex = -1,
15337-        argsLength = arguments.length,
15338-        caches = getArray(),
15339-        indexOf = getIndexOf(),
15340-        trustIndexOf = indexOf === baseIndexOf,
15341-        seen = getArray();
15342-
15343-      while (++argsIndex < argsLength) {
15344-        var value = arguments[argsIndex];
15345-        if (isArray(value) || isArguments(value)) {
15346-          args.push(value);
15347-          caches.push(trustIndexOf && value.length >= largeArraySize &&
15348-            createCache(argsIndex ? args[argsIndex] : seen));
15349-        }
15350-      }
15351-      var array = args[0],
15352-        index = -1,
15353-        length = array ? array.length : 0,
15354-        result = [];
15355-
15356-      outer:
15357-        while (++index < length) {
15358-          var cache = caches[0];
15359-          value = array[index];
15360-
15361-          if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
15362-            argsIndex = argsLength;
15363-            (cache || seen).push(value);
15364-            while (--argsIndex) {
15365-              cache = caches[argsIndex];
15366-              if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
15367-                continue outer;
15368-              }
15369-            }
15370-            result.push(value);
15371-          }
15372-        }
15373-      while (argsLength--) {
15374-        cache = caches[argsLength];
15375-        if (cache) {
15376-          releaseObject(cache);
15377-        }
15378-      }
15379-      releaseArray(caches);
15380-      releaseArray(seen);
15381-      return result;
15382-    }
15383-
15384-    /**
15385-     * Gets the last element or last `n` elements of an array. If a callback is
15386-     * provided elements at the end of the array are returned as long as the
15387-     * callback returns truey. The callback is bound to `thisArg` and invoked
15388-     * with three arguments; (value, index, array).
15389-     *
15390-     * If a property name is provided for `callback` the created "_.pluck" style
15391-     * callback will return the property value of the given element.
15392-     *
15393-     * If an object is provided for `callback` the created "_.where" style callback
15394-     * will return `true` for elements that have the properties of the given object,
15395-     * else `false`.
15396-     *
15397-     * @static
15398-     * @memberOf _
15399-     * @category Arrays
15400-     * @param {Array} array The array to query.
15401-     * @param {Function|Object|number|string} [callback] The function called
15402-     *  per element or the number of elements to return. If a property name or
15403-     *  object is provided it will be used to create a "_.pluck" or "_.where"
15404-     *  style callback, respectively.
15405-     * @param {*} [thisArg] The `this` binding of `callback`.
15406-     * @returns {*} Returns the last element(s) of `array`.
15407-     * @example
15408-     *
15409-     * _.last([1, 2, 3]);
15410-     * // => 3
15411-     *
15412-     * _.last([1, 2, 3], 2);
15413-     * // => [2, 3]
15414-     *
15415-     * _.last([1, 2, 3], function(num) {
15416-     *   return num > 1;
15417-     * });
15418-     * // => [2, 3]
15419-     *
15420-     * var characters = [
15421-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
15422-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
15423-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
15424-     * ];
15425-     *
15426-     * // using "_.pluck" callback shorthand
15427-     * _.pluck(_.last(characters, 'blocked'), 'name');
15428-     * // => ['fred', 'pebbles']
15429-     *
15430-     * // using "_.where" callback shorthand
15431-     * _.last(characters, { 'employer': 'na' });
15432-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
15433-     */
15434-    function last(array, callback, thisArg) {
15435-      var n = 0,
15436-        length = array ? array.length : 0;
15437-
15438-      if (typeof callback != 'number' && callback != null) {
15439-        var index = length;
15440-        callback = lodash.createCallback(callback, thisArg, 3);
15441-        while (index-- && callback(array[index], index, array)) {
15442-          n++;
15443-        }
15444-      } else {
15445-        n = callback;
15446-        if (n == null || thisArg) {
15447-          return array ? array[length - 1] : undefined;
15448-        }
15449-      }
15450-      return slice(array, nativeMax(0, length - n));
15451-    }
15452-
15453-    /**
15454-     * Gets the index at which the last occurrence of `value` is found using strict
15455-     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
15456-     * as the offset from the end of the collection.
15457-     *
15458-     * If a property name is provided for `callback` the created "_.pluck" style
15459-     * callback will return the property value of the given element.
15460-     *
15461-     * If an object is provided for `callback` the created "_.where" style callback
15462-     * will return `true` for elements that have the properties of the given object,
15463-     * else `false`.
15464-     *
15465-     * @static
15466-     * @memberOf _
15467-     * @category Arrays
15468-     * @param {Array} array The array to search.
15469-     * @param {*} value The value to search for.
15470-     * @param {number} [fromIndex=array.length-1] The index to search from.
15471-     * @returns {number} Returns the index of the matched value or `-1`.
15472-     * @example
15473-     *
15474-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
15475-     * // => 4
15476-     *
15477-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
15478-     * // => 1
15479-     */
15480-    function lastIndexOf(array, value, fromIndex) {
15481-      var index = array ? array.length : 0;
15482-      if (typeof fromIndex == 'number') {
15483-        index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
15484-      }
15485-      while (index--) {
15486-        if (array[index] === value) {
15487-          return index;
15488-        }
15489-      }
15490-      return -1;
15491-    }
15492-
15493-    /**
15494-     * Removes all provided values from the given array using strict equality for
15495-     * comparisons, i.e. `===`.
15496-     *
15497-     * @static
15498-     * @memberOf _
15499-     * @category Arrays
15500-     * @param {Array} array The array to modify.
15501-     * @param {...*} [value] The values to remove.
15502-     * @returns {Array} Returns `array`.
15503-     * @example
15504-     *
15505-     * var array = [1, 2, 3, 1, 2, 3];
15506-     * _.pull(array, 2, 3);
15507-     * console.log(array);
15508-     * // => [1, 1]
15509-     */
15510-    function pull(array) {
15511-      var args = arguments,
15512-        argsIndex = 0,
15513-        argsLength = args.length,
15514-        length = array ? array.length : 0;
15515-
15516-      while (++argsIndex < argsLength) {
15517-        var index = -1,
15518-          value = args[argsIndex];
15519-        while (++index < length) {
15520-          if (array[index] === value) {
15521-            splice.call(array, index--, 1);
15522-            length--;
15523-          }
15524-        }
15525-      }
15526-      return array;
15527-    }
15528-
15529-    /**
15530-     * Creates an array of numbers (positive and/or negative) progressing from
15531-     * `start` up to but not including `end`. If `start` is less than `stop` a
15532-     * zero-length range is created unless a negative `step` is specified.
15533-     *
15534-     * @static
15535-     * @memberOf _
15536-     * @category Arrays
15537-     * @param {number} [start=0] The start of the range.
15538-     * @param {number} end The end of the range.
15539-     * @param {number} [step=1] The value to increment or decrement by.
15540-     * @returns {Array} Returns a new range array.
15541-     * @example
15542-     *
15543-     * _.range(4);
15544-     * // => [0, 1, 2, 3]
15545-     *
15546-     * _.range(1, 5);
15547-     * // => [1, 2, 3, 4]
15548-     *
15549-     * _.range(0, 20, 5);
15550-     * // => [0, 5, 10, 15]
15551-     *
15552-     * _.range(0, -4, -1);
15553-     * // => [0, -1, -2, -3]
15554-     *
15555-     * _.range(1, 4, 0);
15556-     * // => [1, 1, 1]
15557-     *
15558-     * _.range(0);
15559-     * // => []
15560-     */
15561-    function range(start, end, step) {
15562-      start = +start || 0;
15563-      step = typeof step == 'number' ? step : (+step || 1);
15564-
15565-      if (end == null) {
15566-        end = start;
15567-        start = 0;
15568-      }
15569-      // use `Array(length)` so engines like Chakra and V8 avoid slower modes
15570-      // http://youtu.be/XAqIpGU8ZZk#t=17m25s
15571-      var index = -1,
15572-        length = nativeMax(0, ceil((end - start) / (step || 1))),
15573-        result = Array(length);
15574-
15575-      while (++index < length) {
15576-        result[index] = start;
15577-        start += step;
15578-      }
15579-      return result;
15580-    }
15581-
15582-    /**
15583-     * Removes all elements from an array that the callback returns truey for
15584-     * and returns an array of removed elements. The callback is bound to `thisArg`
15585-     * and invoked with three arguments; (value, index, array).
15586-     *
15587-     * If a property name is provided for `callback` the created "_.pluck" style
15588-     * callback will return the property value of the given element.
15589-     *
15590-     * If an object is provided for `callback` the created "_.where" style callback
15591-     * will return `true` for elements that have the properties of the given object,
15592-     * else `false`.
15593-     *
15594-     * @static
15595-     * @memberOf _
15596-     * @category Arrays
15597-     * @param {Array} array The array to modify.
15598-     * @param {Function|Object|string} [callback=identity] The function called
15599-     *  per iteration. If a property name or object is provided it will be used
15600-     *  to create a "_.pluck" or "_.where" style callback, respectively.
15601-     * @param {*} [thisArg] The `this` binding of `callback`.
15602-     * @returns {Array} Returns a new array of removed elements.
15603-     * @example
15604-     *
15605-     * var array = [1, 2, 3, 4, 5, 6];
15606-     * var evens = _.remove(array, function(num) { return num % 2 == 0; });
15607-     *
15608-     * console.log(array);
15609-     * // => [1, 3, 5]
15610-     *
15611-     * console.log(evens);
15612-     * // => [2, 4, 6]
15613-     */
15614-    function remove(array, callback, thisArg) {
15615-      var index = -1,
15616-        length = array ? array.length : 0,
15617-        result = [];
15618-
15619-      callback = lodash.createCallback(callback, thisArg, 3);
15620-      while (++index < length) {
15621-        var value = array[index];
15622-        if (callback(value, index, array)) {
15623-          result.push(value);
15624-          splice.call(array, index--, 1);
15625-          length--;
15626-        }
15627-      }
15628-      return result;
15629-    }
15630-
15631-    /**
15632-     * The opposite of `_.initial` this method gets all but the first element or
15633-     * first `n` elements of an array. If a callback function is provided elements
15634-     * at the beginning of the array are excluded from the result as long as the
15635-     * callback returns truey. The callback is bound to `thisArg` and invoked
15636-     * with three arguments; (value, index, array).
15637-     *
15638-     * If a property name is provided for `callback` the created "_.pluck" style
15639-     * callback will return the property value of the given element.
15640-     *
15641-     * If an object is provided for `callback` the created "_.where" style callback
15642-     * will return `true` for elements that have the properties of the given object,
15643-     * else `false`.
15644-     *
15645-     * @static
15646-     * @memberOf _
15647-     * @alias drop, tail
15648-     * @category Arrays
15649-     * @param {Array} array The array to query.
15650-     * @param {Function|Object|number|string} [callback=1] The function called
15651-     *  per element or the number of elements to exclude. If a property name or
15652-     *  object is provided it will be used to create a "_.pluck" or "_.where"
15653-     *  style callback, respectively.
15654-     * @param {*} [thisArg] The `this` binding of `callback`.
15655-     * @returns {Array} Returns a slice of `array`.
15656-     * @example
15657-     *
15658-     * _.rest([1, 2, 3]);
15659-     * // => [2, 3]
15660-     *
15661-     * _.rest([1, 2, 3], 2);
15662-     * // => [3]
15663-     *
15664-     * _.rest([1, 2, 3], function(num) {
15665-     *   return num < 3;
15666-     * });
15667-     * // => [3]
15668-     *
15669-     * var characters = [
15670-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
15671-     *   { 'name': 'fred',    'blocked': false,  'employer': 'slate' },
15672-     *   { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
15673-     * ];
15674-     *
15675-     * // using "_.pluck" callback shorthand
15676-     * _.pluck(_.rest(characters, 'blocked'), 'name');
15677-     * // => ['fred', 'pebbles']
15678-     *
15679-     * // using "_.where" callback shorthand
15680-     * _.rest(characters, { 'employer': 'slate' });
15681-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
15682-     */
15683-    function rest(array, callback, thisArg) {
15684-      if (typeof callback != 'number' && callback != null) {
15685-        var n = 0,
15686-          index = -1,
15687-          length = array ? array.length : 0;
15688-
15689-        callback = lodash.createCallback(callback, thisArg, 3);
15690-        while (++index < length && callback(array[index], index, array)) {
15691-          n++;
15692-        }
15693-      } else {
15694-        n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
15695-      }
15696-      return slice(array, n);
15697-    }
15698-
15699-    /**
15700-     * Uses a binary search to determine the smallest index at which a value
15701-     * should be inserted into a given sorted array in order to maintain the sort
15702-     * order of the array. If a callback is provided it will be executed for
15703-     * `value` and each element of `array` to compute their sort ranking. The
15704-     * callback is bound to `thisArg` and invoked with one argument; (value).
15705-     *
15706-     * If a property name is provided for `callback` the created "_.pluck" style
15707-     * callback will return the property value of the given element.
15708-     *
15709-     * If an object is provided for `callback` the created "_.where" style callback
15710-     * will return `true` for elements that have the properties of the given object,
15711-     * else `false`.
15712-     *
15713-     * @static
15714-     * @memberOf _
15715-     * @category Arrays
15716-     * @param {Array} array The array to inspect.
15717-     * @param {*} value The value to evaluate.
15718-     * @param {Function|Object|string} [callback=identity] The function called
15719-     *  per iteration. If a property name or object is provided it will be used
15720-     *  to create a "_.pluck" or "_.where" style callback, respectively.
15721-     * @param {*} [thisArg] The `this` binding of `callback`.
15722-     * @returns {number} Returns the index at which `value` should be inserted
15723-     *  into `array`.
15724-     * @example
15725-     *
15726-     * _.sortedIndex([20, 30, 50], 40);
15727-     * // => 2
15728-     *
15729-     * // using "_.pluck" callback shorthand
15730-     * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
15731-     * // => 2
15732-     *
15733-     * var dict = {
15734-     *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
15735-     * };
15736-     *
15737-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
15738-     *   return dict.wordToNumber[word];
15739-     * });
15740-     * // => 2
15741-     *
15742-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
15743-     *   return this.wordToNumber[word];
15744-     * }, dict);
15745-     * // => 2
15746-     */
15747-    function sortedIndex(array, value, callback, thisArg) {
15748-      var low = 0,
15749-        high = array ? array.length : low;
15750-
15751-      // explicitly reference `identity` for better inlining in Firefox
15752-      callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
15753-      value = callback(value);
15754-
15755-      while (low < high) {
15756-        var mid = (low + high) >>> 1;
15757-        (callback(array[mid]) < value)
15758-          ? low = mid + 1
15759-          : high = mid;
15760-      }
15761-      return low;
15762-    }
15763-
15764-    /**
15765-     * Creates an array of unique values, in order, of the provided arrays using
15766-     * strict equality for comparisons, i.e. `===`.
15767-     *
15768-     * @static
15769-     * @memberOf _
15770-     * @category Arrays
15771-     * @param {...Array} [array] The arrays to inspect.
15772-     * @returns {Array} Returns an array of combined values.
15773-     * @example
15774-     *
15775-     * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
15776-     * // => [1, 2, 3, 5, 4]
15777-     */
15778-    function union() {
15779-      return baseUniq(baseFlatten(arguments, true, true));
15780-    }
15781-
15782-    /**
15783-     * Creates a duplicate-value-free version of an array using strict equality
15784-     * for comparisons, i.e. `===`. If the array is sorted, providing
15785-     * `true` for `isSorted` will use a faster algorithm. If a callback is provided
15786-     * each element of `array` is passed through the callback before uniqueness
15787-     * is computed. The callback is bound to `thisArg` and invoked with three
15788-     * arguments; (value, index, array).
15789-     *
15790-     * If a property name is provided for `callback` the created "_.pluck" style
15791-     * callback will return the property value of the given element.
15792-     *
15793-     * If an object is provided for `callback` the created "_.where" style callback
15794-     * will return `true` for elements that have the properties of the given object,
15795-     * else `false`.
15796-     *
15797-     * @static
15798-     * @memberOf _
15799-     * @alias unique
15800-     * @category Arrays
15801-     * @param {Array} array The array to process.
15802-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
15803-     * @param {Function|Object|string} [callback=identity] The function called
15804-     *  per iteration. If a property name or object is provided it will be used
15805-     *  to create a "_.pluck" or "_.where" style callback, respectively.
15806-     * @param {*} [thisArg] The `this` binding of `callback`.
15807-     * @returns {Array} Returns a duplicate-value-free array.
15808-     * @example
15809-     *
15810-     * _.uniq([1, 2, 1, 3, 1]);
15811-     * // => [1, 2, 3]
15812-     *
15813-     * _.uniq([1, 1, 2, 2, 3], true);
15814-     * // => [1, 2, 3]
15815-     *
15816-     * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
15817-     * // => ['A', 'b', 'C']
15818-     *
15819-     * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
15820-     * // => [1, 2.5, 3]
15821-     *
15822-     * // using "_.pluck" callback shorthand
15823-     * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
15824-     * // => [{ 'x': 1 }, { 'x': 2 }]
15825-     */
15826-    function uniq(array, isSorted, callback, thisArg) {
15827-      // juggle arguments
15828-      if (typeof isSorted != 'boolean' && isSorted != null) {
15829-        thisArg = callback;
15830-        callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
15831-        isSorted = false;
15832-      }
15833-      if (callback != null) {
15834-        callback = lodash.createCallback(callback, thisArg, 3);
15835-      }
15836-      return baseUniq(array, isSorted, callback);
15837-    }
15838-
15839-    /**
15840-     * Creates an array excluding all provided values using strict equality for
15841-     * comparisons, i.e. `===`.
15842-     *
15843-     * @static
15844-     * @memberOf _
15845-     * @category Arrays
15846-     * @param {Array} array The array to filter.
15847-     * @param {...*} [value] The values to exclude.
15848-     * @returns {Array} Returns a new array of filtered values.
15849-     * @example
15850-     *
15851-     * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
15852-     * // => [2, 3, 4]
15853-     */
15854-    function without(array) {
15855-      return baseDifference(array, slice(arguments, 1));
15856-    }
15857-
15858-    /**
15859-     * Creates an array that is the symmetric difference of the provided arrays.
15860-     * See http://en.wikipedia.org/wiki/Symmetric_difference.
15861-     *
15862-     * @static
15863-     * @memberOf _
15864-     * @category Arrays
15865-     * @param {...Array} [array] The arrays to inspect.
15866-     * @returns {Array} Returns an array of values.
15867-     * @example
15868-     *
15869-     * _.xor([1, 2, 3], [5, 2, 1, 4]);
15870-     * // => [3, 5, 4]
15871-     *
15872-     * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
15873-     * // => [1, 4, 5]
15874-     */
15875-    function xor() {
15876-      var index = -1,
15877-        length = arguments.length;
15878-
15879-      while (++index < length) {
15880-        var array = arguments[index];
15881-        if (isArray(array) || isArguments(array)) {
15882-          var result = result
15883-            ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
15884-            : array;
15885-        }
15886-      }
15887-      return result || [];
15888-    }
15889-
15890-    /**
15891-     * Creates an array of grouped elements, the first of which contains the first
15892-     * elements of the given arrays, the second of which contains the second
15893-     * elements of the given arrays, and so on.
15894-     *
15895-     * @static
15896-     * @memberOf _
15897-     * @alias unzip
15898-     * @category Arrays
15899-     * @param {...Array} [array] Arrays to process.
15900-     * @returns {Array} Returns a new array of grouped elements.
15901-     * @example
15902-     *
15903-     * _.zip(['fred', 'barney'], [30, 40], [true, false]);
15904-     * // => [['fred', 30, true], ['barney', 40, false]]
15905-     */
15906-    function zip() {
15907-      var array = arguments.length > 1 ? arguments : arguments[0],
15908-        index = -1,
15909-        length = array ? max(pluck(array, 'length')) : 0,
15910-        result = Array(length < 0 ? 0 : length);
15911-
15912-      while (++index < length) {
15913-        result[index] = pluck(array, index);
15914-      }
15915-      return result;
15916-    }
15917-
15918-    /**
15919-     * Creates an object composed from arrays of `keys` and `values`. Provide
15920-     * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
15921-     * or two arrays, one of `keys` and one of corresponding `values`.
15922-     *
15923-     * @static
15924-     * @memberOf _
15925-     * @alias object
15926-     * @category Arrays
15927-     * @param {Array} keys The array of keys.
15928-     * @param {Array} [values=[]] The array of values.
15929-     * @returns {Object} Returns an object composed of the given keys and
15930-     *  corresponding values.
15931-     * @example
15932-     *
15933-     * _.zipObject(['fred', 'barney'], [30, 40]);
15934-     * // => { 'fred': 30, 'barney': 40 }
15935-     */
15936-    function zipObject(keys, values) {
15937-      var index = -1,
15938-        length = keys ? keys.length : 0,
15939-        result = {};
15940-
15941-      if (!values && length && !isArray(keys[0])) {
15942-        values = [];
15943-      }
15944-      while (++index < length) {
15945-        var key = keys[index];
15946-        if (values) {
15947-          result[key] = values[index];
15948-        } else if (key) {
15949-          result[key[0]] = key[1];
15950-        }
15951-      }
15952-      return result;
15953-    }
15954-
15955-    /*--------------------------------------------------------------------------*/
15956-
15957-    /**
15958-     * Creates a function that executes `func`, with  the `this` binding and
15959-     * arguments of the created function, only after being called `n` times.
15960-     *
15961-     * @static
15962-     * @memberOf _
15963-     * @category Functions
15964-     * @param {number} n The number of times the function must be called before
15965-     *  `func` is executed.
15966-     * @param {Function} func The function to restrict.
15967-     * @returns {Function} Returns the new restricted function.
15968-     * @example
15969-     *
15970-     * var saves = ['profile', 'settings'];
15971-     *
15972-     * var done = _.after(saves.length, function() {
15973-     *   console.log('Done saving!');
15974-     * });
15975-     *
15976-     * _.forEach(saves, function(type) {
15977-     *   asyncSave({ 'type': type, 'complete': done });
15978-     * });
15979-     * // => logs 'Done saving!', after all saves have completed
15980-     */
15981-    function after(n, func) {
15982-      if (!isFunction(func)) {
15983-        throw new TypeError;
15984-      }
15985-      return function() {
15986-        if (--n < 1) {
15987-          return func.apply(this, arguments);
15988-        }
15989-      };
15990-    }
15991-
15992-    /**
15993-     * Creates a function that, when called, invokes `func` with the `this`
15994-     * binding of `thisArg` and prepends any additional `bind` arguments to those
15995-     * provided to the bound function.
15996-     *
15997-     * @static
15998-     * @memberOf _
15999-     * @category Functions
16000-     * @param {Function} func The function to bind.
16001-     * @param {*} [thisArg] The `this` binding of `func`.
16002-     * @param {...*} [arg] Arguments to be partially applied.
16003-     * @returns {Function} Returns the new bound function.
16004-     * @example
16005-     *
16006-     * var func = function(greeting) {
16007-     *   return greeting + ' ' + this.name;
16008-     * };
16009-     *
16010-     * func = _.bind(func, { 'name': 'fred' }, 'hi');
16011-     * func();
16012-     * // => 'hi fred'
16013-     */
16014-    function bind(func, thisArg) {
16015-      return arguments.length > 2
16016-        ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
16017-        : createWrapper(func, 1, null, null, thisArg);
16018-    }
16019-
16020-    /**
16021-     * Binds methods of an object to the object itself, overwriting the existing
16022-     * method. Method names may be specified as individual arguments or as arrays
16023-     * of method names. If no method names are provided all the function properties
16024-     * of `object` will be bound.
16025-     *
16026-     * @static
16027-     * @memberOf _
16028-     * @category Functions
16029-     * @param {Object} object The object to bind and assign the bound methods to.
16030-     * @param {...string} [methodName] The object method names to
16031-     *  bind, specified as individual method names or arrays of method names.
16032-     * @returns {Object} Returns `object`.
16033-     * @example
16034-     *
16035-     * var view = {
16036-     *   'label': 'docs',
16037-     *   'onClick': function() { console.log('clicked ' + this.label); }
16038-     * };
16039-     *
16040-     * _.bindAll(view);
16041-     * jQuery('#docs').on('click', view.onClick);
16042-     * // => logs 'clicked docs', when the button is clicked
16043-     */
16044-    function bindAll(object) {
16045-      var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
16046-        index = -1,
16047-        length = funcs.length;
16048-
16049-      while (++index < length) {
16050-        var key = funcs[index];
16051-        object[key] = createWrapper(object[key], 1, null, null, object);
16052-      }
16053-      return object;
16054-    }
16055-
16056-    /**
16057-     * Creates a function that, when called, invokes the method at `object[key]`
16058-     * and prepends any additional `bindKey` arguments to those provided to the bound
16059-     * function. This method differs from `_.bind` by allowing bound functions to
16060-     * reference methods that will be redefined or don't yet exist.
16061-     * See http://michaux.ca/articles/lazy-function-definition-pattern.
16062-     *
16063-     * @static
16064-     * @memberOf _
16065-     * @category Functions
16066-     * @param {Object} object The object the method belongs to.
16067-     * @param {string} key The key of the method.
16068-     * @param {...*} [arg] Arguments to be partially applied.
16069-     * @returns {Function} Returns the new bound function.
16070-     * @example
16071-     *
16072-     * var object = {
16073-     *   'name': 'fred',
16074-     *   'greet': function(greeting) {
16075-     *     return greeting + ' ' + this.name;
16076-     *   }
16077-     * };
16078-     *
16079-     * var func = _.bindKey(object, 'greet', 'hi');
16080-     * func();
16081-     * // => 'hi fred'
16082-     *
16083-     * object.greet = function(greeting) {
16084-     *   return greeting + 'ya ' + this.name + '!';
16085-     * };
16086-     *
16087-     * func();
16088-     * // => 'hiya fred!'
16089-     */
16090-    function bindKey(object, key) {
16091-      return arguments.length > 2
16092-        ? createWrapper(key, 19, slice(arguments, 2), null, object)
16093-        : createWrapper(key, 3, null, null, object);
16094-    }
16095-
16096-    /**
16097-     * Creates a function that is the composition of the provided functions,
16098-     * where each function consumes the return value of the function that follows.
16099-     * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
16100-     * Each function is executed with the `this` binding of the composed function.
16101-     *
16102-     * @static
16103-     * @memberOf _
16104-     * @category Functions
16105-     * @param {...Function} [func] Functions to compose.
16106-     * @returns {Function} Returns the new composed function.
16107-     * @example
16108-     *
16109-     * var realNameMap = {
16110-     *   'pebbles': 'penelope'
16111-     * };
16112-     *
16113-     * var format = function(name) {
16114-     *   name = realNameMap[name.toLowerCase()] || name;
16115-     *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
16116-     * };
16117-     *
16118-     * var greet = function(formatted) {
16119-     *   return 'Hiya ' + formatted + '!';
16120-     * };
16121-     *
16122-     * var welcome = _.compose(greet, format);
16123-     * welcome('pebbles');
16124-     * // => 'Hiya Penelope!'
16125-     */
16126-    function compose() {
16127-      var funcs = arguments,
16128-        length = funcs.length;
16129-
16130-      while (length--) {
16131-        if (!isFunction(funcs[length])) {
16132-          throw new TypeError;
16133-        }
16134-      }
16135-      return function() {
16136-        var args = arguments,
16137-          length = funcs.length;
16138-
16139-        while (length--) {
16140-          args = [funcs[length].apply(this, args)];
16141-        }
16142-        return args[0];
16143-      };
16144-    }
16145-
16146-    /**
16147-     * Creates a function which accepts one or more arguments of `func` that when
16148-     * invoked either executes `func` returning its result, if all `func` arguments
16149-     * have been provided, or returns a function that accepts one or more of the
16150-     * remaining `func` arguments, and so on. The arity of `func` can be specified
16151-     * if `func.length` is not sufficient.
16152-     *
16153-     * @static
16154-     * @memberOf _
16155-     * @category Functions
16156-     * @param {Function} func The function to curry.
16157-     * @param {number} [arity=func.length] The arity of `func`.
16158-     * @returns {Function} Returns the new curried function.
16159-     * @example
16160-     *
16161-     * var curried = _.curry(function(a, b, c) {
16162-     *   console.log(a + b + c);
16163-     * });
16164-     *
16165-     * curried(1)(2)(3);
16166-     * // => 6
16167-     *
16168-     * curried(1, 2)(3);
16169-     * // => 6
16170-     *
16171-     * curried(1, 2, 3);
16172-     * // => 6
16173-     */
16174-    function curry(func, arity) {
16175-      arity = typeof arity == 'number' ? arity : (+arity || func.length);
16176-      return createWrapper(func, 4, null, null, null, arity);
16177-    }
16178-
16179-    /**
16180-     * Creates a function that will delay the execution of `func` until after
16181-     * `wait` milliseconds have elapsed since the last time it was invoked.
16182-     * Provide an options object to indicate that `func` should be invoked on
16183-     * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
16184-     * to the debounced function will return the result of the last `func` call.
16185-     *
16186-     * Note: If `leading` and `trailing` options are `true` `func` will be called
16187-     * on the trailing edge of the timeout only if the the debounced function is
16188-     * invoked more than once during the `wait` timeout.
16189-     *
16190-     * @static
16191-     * @memberOf _
16192-     * @category Functions
16193-     * @param {Function} func The function to debounce.
16194-     * @param {number} wait The number of milliseconds to delay.
16195-     * @param {Object} [options] The options object.
16196-     * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
16197-     * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
16198-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
16199-     * @returns {Function} Returns the new debounced function.
16200-     * @example
16201-     *
16202-     * // avoid costly calculations while the window size is in flux
16203-     * var lazyLayout = _.debounce(calculateLayout, 150);
16204-     * jQuery(window).on('resize', lazyLayout);
16205-     *
16206-     * // execute `sendMail` when the click event is fired, debouncing subsequent calls
16207-     * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
16208-     *   'leading': true,
16209-     *   'trailing': false
16210-     * });
16211-     *
16212-     * // ensure `batchLog` is executed once after 1 second of debounced calls
16213-     * var source = new EventSource('/stream');
16214-     * source.addEventListener('message', _.debounce(batchLog, 250, {
16215-     *   'maxWait': 1000
16216-     * }, false);
16217-     */
16218-    function debounce(func, wait, options) {
16219-      var args,
16220-        maxTimeoutId,
16221-        result,
16222-        stamp,
16223-        thisArg,
16224-        timeoutId,
16225-        trailingCall,
16226-        lastCalled = 0,
16227-        maxWait = false,
16228-        trailing = true;
16229-
16230-      if (!isFunction(func)) {
16231-        throw new TypeError;
16232-      }
16233-      wait = nativeMax(0, wait) || 0;
16234-      if (options === true) {
16235-        var leading = true;
16236-        trailing = false;
16237-      } else if (isObject(options)) {
16238-        leading = options.leading;
16239-        maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
16240-        trailing = 'trailing' in options ? options.trailing : trailing;
16241-      }
16242-      var delayed = function() {
16243-        var remaining = wait - (now() - stamp);
16244-        if (remaining <= 0) {
16245-          if (maxTimeoutId) {
16246-            clearTimeout(maxTimeoutId);
16247-          }
16248-          var isCalled = trailingCall;
16249-          maxTimeoutId = timeoutId = trailingCall = undefined;
16250-          if (isCalled) {
16251-            lastCalled = now();
16252-            result = func.apply(thisArg, args);
16253-            if (!timeoutId && !maxTimeoutId) {
16254-              args = thisArg = null;
16255-            }
16256-          }
16257-        } else {
16258-          timeoutId = setTimeout(delayed, remaining);
16259-        }
16260-      };
16261-
16262-      var maxDelayed = function() {
16263-        if (timeoutId) {
16264-          clearTimeout(timeoutId);
16265-        }
16266-        maxTimeoutId = timeoutId = trailingCall = undefined;
16267-        if (trailing || (maxWait !== wait)) {
16268-          lastCalled = now();
16269-          result = func.apply(thisArg, args);
16270-          if (!timeoutId && !maxTimeoutId) {
16271-            args = thisArg = null;
16272-          }
16273-        }
16274-      };
16275-
16276-      return function() {
16277-        args = arguments;
16278-        stamp = now();
16279-        thisArg = this;
16280-        trailingCall = trailing && (timeoutId || !leading);
16281-
16282-        if (maxWait === false) {
16283-          var leadingCall = leading && !timeoutId;
16284-        } else {
16285-          if (!maxTimeoutId && !leading) {
16286-            lastCalled = stamp;
16287-          }
16288-          var remaining = maxWait - (stamp - lastCalled),
16289-            isCalled = remaining <= 0;
16290-
16291-          if (isCalled) {
16292-            if (maxTimeoutId) {
16293-              maxTimeoutId = clearTimeout(maxTimeoutId);
16294-            }
16295-            lastCalled = stamp;
16296-            result = func.apply(thisArg, args);
16297-          }
16298-          else if (!maxTimeoutId) {
16299-            maxTimeoutId = setTimeout(maxDelayed, remaining);
16300-          }
16301-        }
16302-        if (isCalled && timeoutId) {
16303-          timeoutId = clearTimeout(timeoutId);
16304-        }
16305-        else if (!timeoutId && wait !== maxWait) {
16306-          timeoutId = setTimeout(delayed, wait);
16307-        }
16308-        if (leadingCall) {
16309-          isCalled = true;
16310-          result = func.apply(thisArg, args);
16311-        }
16312-        if (isCalled && !timeoutId && !maxTimeoutId) {
16313-          args = thisArg = null;
16314-        }
16315-        return result;
16316-      };
16317-    }
16318-
16319-    /**
16320-     * Defers executing the `func` function until the current call stack has cleared.
16321-     * Additional arguments will be provided to `func` when it is invoked.
16322-     *
16323-     * @static
16324-     * @memberOf _
16325-     * @category Functions
16326-     * @param {Function} func The function to defer.
16327-     * @param {...*} [arg] Arguments to invoke the function with.
16328-     * @returns {number} Returns the timer id.
16329-     * @example
16330-     *
16331-     * _.defer(function(text) { console.log(text); }, 'deferred');
16332-     * // logs 'deferred' after one or more milliseconds
16333-     */
16334-    function defer(func) {
16335-      if (!isFunction(func)) {
16336-        throw new TypeError;
16337-      }
16338-      var args = slice(arguments, 1);
16339-      return setTimeout(function() { func.apply(undefined, args); }, 1);
16340-    }
16341-
16342-    /**
16343-     * Executes the `func` function after `wait` milliseconds. Additional arguments
16344-     * will be provided to `func` when it is invoked.
16345-     *
16346-     * @static
16347-     * @memberOf _
16348-     * @category Functions
16349-     * @param {Function} func The function to delay.
16350-     * @param {number} wait The number of milliseconds to delay execution.
16351-     * @param {...*} [arg] Arguments to invoke the function with.
16352-     * @returns {number} Returns the timer id.
16353-     * @example
16354-     *
16355-     * _.delay(function(text) { console.log(text); }, 1000, 'later');
16356-     * // => logs 'later' after one second
16357-     */
16358-    function delay(func, wait) {
16359-      if (!isFunction(func)) {
16360-        throw new TypeError;
16361-      }
16362-      var args = slice(arguments, 2);
16363-      return setTimeout(function() { func.apply(undefined, args); }, wait);
16364-    }
16365-
16366-    /**
16367-     * Creates a function that memoizes the result of `func`. If `resolver` is
16368-     * provided it will be used to determine the cache key for storing the result
16369-     * based on the arguments provided to the memoized function. By default, the
16370-     * first argument provided to the memoized function is used as the cache key.
16371-     * The `func` is executed with the `this` binding of the memoized function.
16372-     * The result cache is exposed as the `cache` property on the memoized function.
16373-     *
16374-     * @static
16375-     * @memberOf _
16376-     * @category Functions
16377-     * @param {Function} func The function to have its output memoized.
16378-     * @param {Function} [resolver] A function used to resolve the cache key.
16379-     * @returns {Function} Returns the new memoizing function.
16380-     * @example
16381-     *
16382-     * var fibonacci = _.memoize(function(n) {
16383-     *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
16384-     * });
16385-     *
16386-     * fibonacci(9)
16387-     * // => 34
16388-     *
16389-     * var data = {
16390-     *   'fred': { 'name': 'fred', 'age': 40 },
16391-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
16392-     * };
16393-     *
16394-     * // modifying the result cache
16395-     * var get = _.memoize(function(name) { return data[name]; }, _.identity);
16396-     * get('pebbles');
16397-     * // => { 'name': 'pebbles', 'age': 1 }
16398-     *
16399-     * get.cache.pebbles.name = 'penelope';
16400-     * get('pebbles');
16401-     * // => { 'name': 'penelope', 'age': 1 }
16402-     */
16403-    function memoize(func, resolver) {
16404-      if (!isFunction(func)) {
16405-        throw new TypeError;
16406-      }
16407-      var memoized = function() {
16408-        var cache = memoized.cache,
16409-          key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
16410-
16411-        return hasOwnProperty.call(cache, key)
16412-          ? cache[key]
16413-          : (cache[key] = func.apply(this, arguments));
16414-      }
16415-      memoized.cache = {};
16416-      return memoized;
16417-    }
16418-
16419-    /**
16420-     * Creates a function that is restricted to execute `func` once. Repeat calls to
16421-     * the function will return the value of the first call. The `func` is executed
16422-     * with the `this` binding of the created function.
16423-     *
16424-     * @static
16425-     * @memberOf _
16426-     * @category Functions
16427-     * @param {Function} func The function to restrict.
16428-     * @returns {Function} Returns the new restricted function.
16429-     * @example
16430-     *
16431-     * var initialize = _.once(createApplication);
16432-     * initialize();
16433-     * initialize();
16434-     * // `initialize` executes `createApplication` once
16435-     */
16436-    function once(func) {
16437-      var ran,
16438-        result;
16439-
16440-      if (!isFunction(func)) {
16441-        throw new TypeError;
16442-      }
16443-      return function() {
16444-        if (ran) {
16445-          return result;
16446-        }
16447-        ran = true;
16448-        result = func.apply(this, arguments);
16449-
16450-        // clear the `func` variable so the function may be garbage collected
16451-        func = null;
16452-        return result;
16453-      };
16454-    }
16455-
16456-    /**
16457-     * Creates a function that, when called, invokes `func` with any additional
16458-     * `partial` arguments prepended to those provided to the new function. This
16459-     * method is similar to `_.bind` except it does **not** alter the `this` binding.
16460-     *
16461-     * @static
16462-     * @memberOf _
16463-     * @category Functions
16464-     * @param {Function} func The function to partially apply arguments to.
16465-     * @param {...*} [arg] Arguments to be partially applied.
16466-     * @returns {Function} Returns the new partially applied function.
16467-     * @example
16468-     *
16469-     * var greet = function(greeting, name) { return greeting + ' ' + name; };
16470-     * var hi = _.partial(greet, 'hi');
16471-     * hi('fred');
16472-     * // => 'hi fred'
16473-     */
16474-    function partial(func) {
16475-      return createWrapper(func, 16, slice(arguments, 1));
16476-    }
16477-
16478-    /**
16479-     * This method is like `_.partial` except that `partial` arguments are
16480-     * appended to those provided to the new function.
16481-     *
16482-     * @static
16483-     * @memberOf _
16484-     * @category Functions
16485-     * @param {Function} func The function to partially apply arguments to.
16486-     * @param {...*} [arg] Arguments to be partially applied.
16487-     * @returns {Function} Returns the new partially applied function.
16488-     * @example
16489-     *
16490-     * var defaultsDeep = _.partialRight(_.merge, _.defaults);
16491-     *
16492-     * var options = {
16493-     *   'variable': 'data',
16494-     *   'imports': { 'jq': $ }
16495-     * };
16496-     *
16497-     * defaultsDeep(options, _.templateSettings);
16498-     *
16499-     * options.variable
16500-     * // => 'data'
16501-     *
16502-     * options.imports
16503-     * // => { '_': _, 'jq': $ }
16504-     */
16505-    function partialRight(func) {
16506-      return createWrapper(func, 32, null, slice(arguments, 1));
16507-    }
16508-
16509-    /**
16510-     * Creates a function that, when executed, will only call the `func` function
16511-     * at most once per every `wait` milliseconds. Provide an options object to
16512-     * indicate that `func` should be invoked on the leading and/or trailing edge
16513-     * of the `wait` timeout. Subsequent calls to the throttled function will
16514-     * return the result of the last `func` call.
16515-     *
16516-     * Note: If `leading` and `trailing` options are `true` `func` will be called
16517-     * on the trailing edge of the timeout only if the the throttled function is
16518-     * invoked more than once during the `wait` timeout.
16519-     *
16520-     * @static
16521-     * @memberOf _
16522-     * @category Functions
16523-     * @param {Function} func The function to throttle.
16524-     * @param {number} wait The number of milliseconds to throttle executions to.
16525-     * @param {Object} [options] The options object.
16526-     * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
16527-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
16528-     * @returns {Function} Returns the new throttled function.
16529-     * @example
16530-     *
16531-     * // avoid excessively updating the position while scrolling
16532-     * var throttled = _.throttle(updatePosition, 100);
16533-     * jQuery(window).on('scroll', throttled);
16534-     *
16535-     * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
16536-     * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
16537-     *   'trailing': false
16538-     * }));
16539-     */
16540-    function throttle(func, wait, options) {
16541-      var leading = true,
16542-        trailing = true;
16543-
16544-      if (!isFunction(func)) {
16545-        throw new TypeError;
16546-      }
16547-      if (options === false) {
16548-        leading = false;
16549-      } else if (isObject(options)) {
16550-        leading = 'leading' in options ? options.leading : leading;
16551-        trailing = 'trailing' in options ? options.trailing : trailing;
16552-      }
16553-      debounceOptions.leading = leading;
16554-      debounceOptions.maxWait = wait;
16555-      debounceOptions.trailing = trailing;
16556-
16557-      return debounce(func, wait, debounceOptions);
16558-    }
16559-
16560-    /**
16561-     * Creates a function that provides `value` to the wrapper function as its
16562-     * first argument. Additional arguments provided to the function are appended
16563-     * to those provided to the wrapper function. The wrapper is executed with
16564-     * the `this` binding of the created function.
16565-     *
16566-     * @static
16567-     * @memberOf _
16568-     * @category Functions
16569-     * @param {*} value The value to wrap.
16570-     * @param {Function} wrapper The wrapper function.
16571-     * @returns {Function} Returns the new function.
16572-     * @example
16573-     *
16574-     * var p = _.wrap(_.escape, function(func, text) {
16575-     *   return '<p>' + func(text) + '</p>';
16576-     * });
16577-     *
16578-     * p('Fred, Wilma, & Pebbles');
16579-     * // => '<p>Fred, Wilma, &amp; Pebbles</p>'
16580-     */
16581-    function wrap(value, wrapper) {
16582-      return createWrapper(wrapper, 16, [value]);
16583-    }
16584-
16585-    /*--------------------------------------------------------------------------*/
16586-
16587-    /**
16588-     * Creates a function that returns `value`.
16589-     *
16590-     * @static
16591-     * @memberOf _
16592-     * @category Utilities
16593-     * @param {*} value The value to return from the new function.
16594-     * @returns {Function} Returns the new function.
16595-     * @example
16596-     *
16597-     * var object = { 'name': 'fred' };
16598-     * var getter = _.constant(object);
16599-     * getter() === object;
16600-     * // => true
16601-     */
16602-    function constant(value) {
16603-      return function() {
16604-        return value;
16605-      };
16606-    }
16607-
16608-    /**
16609-     * Produces a callback bound to an optional `thisArg`. If `func` is a property
16610-     * name the created callback will return the property value for a given element.
16611-     * If `func` is an object the created callback will return `true` for elements
16612-     * that contain the equivalent object properties, otherwise it will return `false`.
16613-     *
16614-     * @static
16615-     * @memberOf _
16616-     * @category Utilities
16617-     * @param {*} [func=identity] The value to convert to a callback.
16618-     * @param {*} [thisArg] The `this` binding of the created callback.
16619-     * @param {number} [argCount] The number of arguments the callback accepts.
16620-     * @returns {Function} Returns a callback function.
16621-     * @example
16622-     *
16623-     * var characters = [
16624-     *   { 'name': 'barney', 'age': 36 },
16625-     *   { 'name': 'fred',   'age': 40 }
16626-     * ];
16627-     *
16628-     * // wrap to create custom callback shorthands
16629-     * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
16630-     *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
16631-     *   return !match ? func(callback, thisArg) : function(object) {
16632-     *     return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
16633-     *   };
16634-     * });
16635-     *
16636-     * _.filter(characters, 'age__gt38');
16637-     * // => [{ 'name': 'fred', 'age': 40 }]
16638-     */
16639-    function createCallback(func, thisArg, argCount) {
16640-      var type = typeof func;
16641-      if (func == null || type == 'function') {
16642-        return baseCreateCallback(func, thisArg, argCount);
16643-      }
16644-      // handle "_.pluck" style callback shorthands
16645-      if (type != 'object') {
16646-        return property(func);
16647-      }
16648-      var props = keys(func),
16649-        key = props[0],
16650-        a = func[key];
16651-
16652-      // handle "_.where" style callback shorthands
16653-      if (props.length == 1 && a === a && !isObject(a)) {
16654-        // fast path the common case of providing an object with a single
16655-        // property containing a primitive value
16656-        return function(object) {
16657-          var b = object[key];
16658-          return a === b && (a !== 0 || (1 / a == 1 / b));
16659-        };
16660-      }
16661-      return function(object) {
16662-        var length = props.length,
16663-          result = false;
16664-
16665-        while (length--) {
16666-          if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
16667-            break;
16668-          }
16669-        }
16670-        return result;
16671-      };
16672-    }
16673-
16674-    /**
16675-     * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
16676-     * corresponding HTML entities.
16677-     *
16678-     * @static
16679-     * @memberOf _
16680-     * @category Utilities
16681-     * @param {string} string The string to escape.
16682-     * @returns {string} Returns the escaped string.
16683-     * @example
16684-     *
16685-     * _.escape('Fred, Wilma, & Pebbles');
16686-     * // => 'Fred, Wilma, &amp; Pebbles'
16687-     */
16688-    function escape(string) {
16689-      return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
16690-    }
16691-
16692-    /**
16693-     * This method returns the first argument provided to it.
16694-     *
16695-     * @static
16696-     * @memberOf _
16697-     * @category Utilities
16698-     * @param {*} value Any value.
16699-     * @returns {*} Returns `value`.
16700-     * @example
16701-     *
16702-     * var object = { 'name': 'fred' };
16703-     * _.identity(object) === object;
16704-     * // => true
16705-     */
16706-    function identity(value) {
16707-      return value;
16708-    }
16709-
16710-    /**
16711-     * Adds function properties of a source object to the destination object.
16712-     * If `object` is a function methods will be added to its prototype as well.
16713-     *
16714-     * @static
16715-     * @memberOf _
16716-     * @category Utilities
16717-     * @param {Function|Object} [object=lodash] object The destination object.
16718-     * @param {Object} source The object of functions to add.
16719-     * @param {Object} [options] The options object.
16720-     * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
16721-     * @example
16722-     *
16723-     * function capitalize(string) {
16724-     *   return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
16725-     * }
16726-     *
16727-     * _.mixin({ 'capitalize': capitalize });
16728-     * _.capitalize('fred');
16729-     * // => 'Fred'
16730-     *
16731-     * _('fred').capitalize().value();
16732-     * // => 'Fred'
16733-     *
16734-     * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
16735-     * _('fred').capitalize();
16736-     * // => 'Fred'
16737-     */
16738-    function mixin(object, source, options) {
16739-      var chain = true,
16740-        methodNames = source && functions(source);
16741-
16742-      if (!source || (!options && !methodNames.length)) {
16743-        if (options == null) {
16744-          options = source;
16745-        }
16746-        ctor = lodashWrapper;
16747-        source = object;
16748-        object = lodash;
16749-        methodNames = functions(source);
16750-      }
16751-      if (options === false) {
16752-        chain = false;
16753-      } else if (isObject(options) && 'chain' in options) {
16754-        chain = options.chain;
16755-      }
16756-      var ctor = object,
16757-        isFunc = isFunction(ctor);
16758-
16759-      forEach(methodNames, function(methodName) {
16760-        var func = object[methodName] = source[methodName];
16761-        if (isFunc) {
16762-          ctor.prototype[methodName] = function() {
16763-            var chainAll = this.__chain__,
16764-              value = this.__wrapped__,
16765-              args = [value];
16766-
16767-            push.apply(args, arguments);
16768-            var result = func.apply(object, args);
16769-            if (chain || chainAll) {
16770-              if (value === result && isObject(result)) {
16771-                return this;
16772-              }
16773-              result = new ctor(result);
16774-              result.__chain__ = chainAll;
16775-            }
16776-            return result;
16777-          };
16778-        }
16779-      });
16780-    }
16781-
16782-    /**
16783-     * Reverts the '_' variable to its previous value and returns a reference to
16784-     * the `lodash` function.
16785-     *
16786-     * @static
16787-     * @memberOf _
16788-     * @category Utilities
16789-     * @returns {Function} Returns the `lodash` function.
16790-     * @example
16791-     *
16792-     * var lodash = _.noConflict();
16793-     */
16794-    function noConflict() {
16795-      context._ = oldDash;
16796-      return this;
16797-    }
16798-
16799-    /**
16800-     * A no-operation function.
16801-     *
16802-     * @static
16803-     * @memberOf _
16804-     * @category Utilities
16805-     * @example
16806-     *
16807-     * var object = { 'name': 'fred' };
16808-     * _.noop(object) === undefined;
16809-     * // => true
16810-     */
16811-    function noop() {
16812-      // no operation performed
16813-    }
16814-
16815-    /**
16816-     * Gets the number of milliseconds that have elapsed since the Unix epoch
16817-     * (1 January 1970 00:00:00 UTC).
16818-     *
16819-     * @static
16820-     * @memberOf _
16821-     * @category Utilities
16822-     * @example
16823-     *
16824-     * var stamp = _.now();
16825-     * _.defer(function() { console.log(_.now() - stamp); });
16826-     * // => logs the number of milliseconds it took for the deferred function to be called
16827-     */
16828-    var now = isNative(now = Date.now) && now || function() {
16829-        return new Date().getTime();
16830-      };
16831-
16832-    /**
16833-     * Converts the given value into an integer of the specified radix.
16834-     * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
16835-     * `value` is a hexadecimal, in which case a `radix` of `16` is used.
16836-     *
16837-     * Note: This method avoids differences in native ES3 and ES5 `parseInt`
16838-     * implementations. See http://es5.github.io/#E.
16839-     *
16840-     * @static
16841-     * @memberOf _
16842-     * @category Utilities
16843-     * @param {string} value The value to parse.
16844-     * @param {number} [radix] The radix used to interpret the value to parse.
16845-     * @returns {number} Returns the new integer value.
16846-     * @example
16847-     *
16848-     * _.parseInt('08');
16849-     * // => 8
16850-     */
16851-    var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
16852-      // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
16853-      return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
16854-    };
16855-
16856-    /**
16857-     * Creates a "_.pluck" style function, which returns the `key` value of a
16858-     * given object.
16859-     *
16860-     * @static
16861-     * @memberOf _
16862-     * @category Utilities
16863-     * @param {string} key The name of the property to retrieve.
16864-     * @returns {Function} Returns the new function.
16865-     * @example
16866-     *
16867-     * var characters = [
16868-     *   { 'name': 'fred',   'age': 40 },
16869-     *   { 'name': 'barney', 'age': 36 }
16870-     * ];
16871-     *
16872-     * var getName = _.property('name');
16873-     *
16874-     * _.map(characters, getName);
16875-     * // => ['barney', 'fred']
16876-     *
16877-     * _.sortBy(characters, getName);
16878-     * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred',   'age': 40 }]
16879-     */
16880-    function property(key) {
16881-      return function(object) {
16882-        return object[key];
16883-      };
16884-    }
16885-
16886-    /**
16887-     * Produces a random number between `min` and `max` (inclusive). If only one
16888-     * argument is provided a number between `0` and the given number will be
16889-     * returned. If `floating` is truey or either `min` or `max` are floats a
16890-     * floating-point number will be returned instead of an integer.
16891-     *
16892-     * @static
16893-     * @memberOf _
16894-     * @category Utilities
16895-     * @param {number} [min=0] The minimum possible value.
16896-     * @param {number} [max=1] The maximum possible value.
16897-     * @param {boolean} [floating=false] Specify returning a floating-point number.
16898-     * @returns {number} Returns a random number.
16899-     * @example
16900-     *
16901-     * _.random(0, 5);
16902-     * // => an integer between 0 and 5
16903-     *
16904-     * _.random(5);
16905-     * // => also an integer between 0 and 5
16906-     *
16907-     * _.random(5, true);
16908-     * // => a floating-point number between 0 and 5
16909-     *
16910-     * _.random(1.2, 5.2);
16911-     * // => a floating-point number between 1.2 and 5.2
16912-     */
16913-    function random(min, max, floating) {
16914-      var noMin = min == null,
16915-        noMax = max == null;
16916-
16917-      if (floating == null) {
16918-        if (typeof min == 'boolean' && noMax) {
16919-          floating = min;
16920-          min = 1;
16921-        }
16922-        else if (!noMax && typeof max == 'boolean') {
16923-          floating = max;
16924-          noMax = true;
16925-        }
16926-      }
16927-      if (noMin && noMax) {
16928-        max = 1;
16929-      }
16930-      min = +min || 0;
16931-      if (noMax) {
16932-        max = min;
16933-        min = 0;
16934-      } else {
16935-        max = +max || 0;
16936-      }
16937-      if (floating || min % 1 || max % 1) {
16938-        var rand = nativeRandom();
16939-        return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
16940-      }
16941-      return baseRandom(min, max);
16942-    }
16943-
16944-    /**
16945-     * Resolves the value of property `key` on `object`. If `key` is a function
16946-     * it will be invoked with the `this` binding of `object` and its result returned,
16947-     * else the property value is returned. If `object` is falsey then `undefined`
16948-     * is returned.
16949-     *
16950-     * @static
16951-     * @memberOf _
16952-     * @category Utilities
16953-     * @param {Object} object The object to inspect.
16954-     * @param {string} key The name of the property to resolve.
16955-     * @returns {*} Returns the resolved value.
16956-     * @example
16957-     *
16958-     * var object = {
16959-     *   'cheese': 'crumpets',
16960-     *   'stuff': function() {
16961-     *     return 'nonsense';
16962-     *   }
16963-     * };
16964-     *
16965-     * _.result(object, 'cheese');
16966-     * // => 'crumpets'
16967-     *
16968-     * _.result(object, 'stuff');
16969-     * // => 'nonsense'
16970-     */
16971-    function result(object, key) {
16972-      if (object) {
16973-        var value = object[key];
16974-        return isFunction(value) ? object[key]() : value;
16975-      }
16976-    }
16977-
16978-    /**
16979-     * A micro-templating method that handles arbitrary delimiters, preserves
16980-     * whitespace, and correctly escapes quotes within interpolated code.
16981-     *
16982-     * Note: In the development build, `_.template` utilizes sourceURLs for easier
16983-     * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
16984-     *
16985-     * For more information on precompiling templates see:
16986-     * http://lodash.com/custom-builds
16987-     *
16988-     * For more information on Chrome extension sandboxes see:
16989-     * http://developer.chrome.com/stable/extensions/sandboxingEval.html
16990-     *
16991-     * @static
16992-     * @memberOf _
16993-     * @category Utilities
16994-     * @param {string} text The template text.
16995-     * @param {Object} data The data object used to populate the text.
16996-     * @param {Object} [options] The options object.
16997-     * @param {RegExp} [options.escape] The "escape" delimiter.
16998-     * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
16999-     * @param {Object} [options.imports] An object to import into the template as local variables.
17000-     * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
17001-     * @param {string} [sourceURL] The sourceURL of the template's compiled source.
17002-     * @param {string} [variable] The data object variable name.
17003-     * @returns {Function|string} Returns a compiled function when no `data` object
17004-     *  is given, else it returns the interpolated text.
17005-     * @example
17006-     *
17007-     * // using the "interpolate" delimiter to create a compiled template
17008-     * var compiled = _.template('hello <%= name %>');
17009-     * compiled({ 'name': 'fred' });
17010-     * // => 'hello fred'
17011-     *
17012-     * // using the "escape" delimiter to escape HTML in data property values
17013-     * _.template('<b><%- value %></b>', { 'value': '<script>' });
17014-     * // => '<b>&lt;script&gt;</b>'
17015-     *
17016-     * // using the "evaluate" delimiter to generate HTML
17017-     * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
17018-     * _.template(list, { 'people': ['fred', 'barney'] });
17019-     * // => '<li>fred</li><li>barney</li>'
17020-     *
17021-     * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
17022-     * _.template('hello ${ name }', { 'name': 'pebbles' });
17023-     * // => 'hello pebbles'
17024-     *
17025-     * // using the internal `print` function in "evaluate" delimiters
17026-     * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
17027-     * // => 'hello barney!'
17028-     *
17029-     * // using a custom template delimiters
17030-     * _.templateSettings = {
17031-     *   'interpolate': /{{([\s\S]+?)}}/g
17032-     * };
17033-     *
17034-     * _.template('hello {{ name }}!', { 'name': 'mustache' });
17035-     * // => 'hello mustache!'
17036-     *
17037-     * // using the `imports` option to import jQuery
17038-     * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
17039-     * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
17040-     * // => '<li>fred</li><li>barney</li>'
17041-     *
17042-     * // using the `sourceURL` option to specify a custom sourceURL for the template
17043-     * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
17044-     * compiled(data);
17045-     * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
17046-     *
17047-     * // using the `variable` option to ensure a with-statement isn't used in the compiled template
17048-     * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
17049-     * compiled.source;
17050-     * // => function(data) {
17051-     *   var __t, __p = '', __e = _.escape;
17052-     *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
17053-     *   return __p;
17054-     * }
17055-     *
17056-     * // using the `source` property to inline compiled templates for meaningful
17057-     * // line numbers in error messages and a stack trace
17058-     * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
17059-     *   var JST = {\
17060-     *     "main": ' + _.template(mainText).source + '\
17061-     *   };\
17062-     * ');
17063-     */
17064-    function template(text, data, options) {
17065-      // based on John Resig's `tmpl` implementation
17066-      // http://ejohn.org/blog/javascript-micro-templating/
17067-      // and Laura Doktorova's doT.js
17068-      // https://github.com/olado/doT
17069-      var settings = lodash.templateSettings;
17070-      text = String(text || '');
17071-
17072-      // avoid missing dependencies when `iteratorTemplate` is not defined
17073-      options = defaults({}, options, settings);
17074-
17075-      var imports = defaults({}, options.imports, settings.imports),
17076-        importsKeys = keys(imports),
17077-        importsValues = values(imports);
17078-
17079-      var isEvaluating,
17080-        index = 0,
17081-        interpolate = options.interpolate || reNoMatch,
17082-        source = "__p += '";
17083-
17084-      // compile the regexp to match each delimiter
17085-      var reDelimiters = RegExp(
17086-        (options.escape || reNoMatch).source + '|' +
17087-        interpolate.source + '|' +
17088-        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
17089-        (options.evaluate || reNoMatch).source + '|$'
17090-        , 'g');
17091-
17092-      text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
17093-        interpolateValue || (interpolateValue = esTemplateValue);
17094-
17095-        // escape characters that cannot be included in string literals
17096-        source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
17097-
17098-        // replace delimiters with snippets
17099-        if (escapeValue) {
17100-          source += "' +\n__e(" + escapeValue + ") +\n'";
17101-        }
17102-        if (evaluateValue) {
17103-          isEvaluating = true;
17104-          source += "';\n" + evaluateValue + ";\n__p += '";
17105-        }
17106-        if (interpolateValue) {
17107-          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
17108-        }
17109-        index = offset + match.length;
17110-
17111-        // the JS engine embedded in Adobe products requires returning the `match`
17112-        // string in order to produce the correct `offset` value
17113-        return match;
17114-      });
17115-
17116-      source += "';\n";
17117-
17118-      // if `variable` is not specified, wrap a with-statement around the generated
17119-      // code to add the data object to the top of the scope chain
17120-      var variable = options.variable,
17121-        hasVariable = variable;
17122-
17123-      if (!hasVariable) {
17124-        variable = 'obj';
17125-        source = 'with (' + variable + ') {\n' + source + '\n}\n';
17126-      }
17127-      // cleanup code by stripping empty strings
17128-      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
17129-        .replace(reEmptyStringMiddle, '$1')
17130-        .replace(reEmptyStringTrailing, '$1;');
17131-
17132-      // frame code as the function body
17133-      source = 'function(' + variable + ') {\n' +
17134-        (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
17135-        "var __t, __p = '', __e = _.escape" +
17136-        (isEvaluating
17137-            ? ', __j = Array.prototype.join;\n' +
17138-          "function print() { __p += __j.call(arguments, '') }\n"
17139-            : ';\n'
17140-        ) +
17141-        source +
17142-        'return __p\n}';
17143-
17144-      // Use a sourceURL for easier debugging.
17145-      // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
17146-      var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
17147-
17148-      try {
17149-        var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
17150-      } catch(e) {
17151-        e.source = source;
17152-        throw e;
17153-      }
17154-      if (data) {
17155-        return result(data);
17156-      }
17157-      // provide the compiled function's source by its `toString` method, in
17158-      // supported environments, or the `source` property as a convenience for
17159-      // inlining compiled templates during the build process
17160-      result.source = source;
17161-      return result;
17162-    }
17163-
17164-    /**
17165-     * Executes the callback `n` times, returning an array of the results
17166-     * of each callback execution. The callback is bound to `thisArg` and invoked
17167-     * with one argument; (index).
17168-     *
17169-     * @static
17170-     * @memberOf _
17171-     * @category Utilities
17172-     * @param {number} n The number of times to execute the callback.
17173-     * @param {Function} callback The function called per iteration.
17174-     * @param {*} [thisArg] The `this` binding of `callback`.
17175-     * @returns {Array} Returns an array of the results of each `callback` execution.
17176-     * @example
17177-     *
17178-     * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
17179-     * // => [3, 6, 4]
17180-     *
17181-     * _.times(3, function(n) { mage.castSpell(n); });
17182-     * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
17183-     *
17184-     * _.times(3, function(n) { this.cast(n); }, mage);
17185-     * // => also calls `mage.castSpell(n)` three times
17186-     */
17187-    function times(n, callback, thisArg) {
17188-      n = (n = +n) > -1 ? n : 0;
17189-      var index = -1,
17190-        result = Array(n);
17191-
17192-      callback = baseCreateCallback(callback, thisArg, 1);
17193-      while (++index < n) {
17194-        result[index] = callback(index);
17195-      }
17196-      return result;
17197-    }
17198-
17199-    /**
17200-     * The inverse of `_.escape` this method converts the HTML entities
17201-     * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
17202-     * corresponding characters.
17203-     *
17204-     * @static
17205-     * @memberOf _
17206-     * @category Utilities
17207-     * @param {string} string The string to unescape.
17208-     * @returns {string} Returns the unescaped string.
17209-     * @example
17210-     *
17211-     * _.unescape('Fred, Barney &amp; Pebbles');
17212-     * // => 'Fred, Barney & Pebbles'
17213-     */
17214-    function unescape(string) {
17215-      return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
17216-    }
17217-
17218-    /**
17219-     * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
17220-     *
17221-     * @static
17222-     * @memberOf _
17223-     * @category Utilities
17224-     * @param {string} [prefix] The value to prefix the ID with.
17225-     * @returns {string} Returns the unique ID.
17226-     * @example
17227-     *
17228-     * _.uniqueId('contact_');
17229-     * // => 'contact_104'
17230-     *
17231-     * _.uniqueId();
17232-     * // => '105'
17233-     */
17234-    function uniqueId(prefix) {
17235-      var id = ++idCounter;
17236-      return String(prefix == null ? '' : prefix) + id;
17237-    }
17238-
17239-    /*--------------------------------------------------------------------------*/
17240-
17241-    /**
17242-     * Creates a `lodash` object that wraps the given value with explicit
17243-     * method chaining enabled.
17244-     *
17245-     * @static
17246-     * @memberOf _
17247-     * @category Chaining
17248-     * @param {*} value The value to wrap.
17249-     * @returns {Object} Returns the wrapper object.
17250-     * @example
17251-     *
17252-     * var characters = [
17253-     *   { 'name': 'barney',  'age': 36 },
17254-     *   { 'name': 'fred',    'age': 40 },
17255-     *   { 'name': 'pebbles', 'age': 1 }
17256-     * ];
17257-     *
17258-     * var youngest = _.chain(characters)
17259-     *     .sortBy('age')
17260-     *     .map(function(chr) { return chr.name + ' is ' + chr.age; })
17261-     *     .first()
17262-     *     .value();
17263-     * // => 'pebbles is 1'
17264-     */
17265-    function chain(value) {
17266-      value = new lodashWrapper(value);
17267-      value.__chain__ = true;
17268-      return value;
17269-    }
17270-
17271-    /**
17272-     * Invokes `interceptor` with the `value` as the first argument and then
17273-     * returns `value`. The purpose of this method is to "tap into" a method
17274-     * chain in order to perform operations on intermediate results within
17275-     * the chain.
17276-     *
17277-     * @static
17278-     * @memberOf _
17279-     * @category Chaining
17280-     * @param {*} value The value to provide to `interceptor`.
17281-     * @param {Function} interceptor The function to invoke.
17282-     * @returns {*} Returns `value`.
17283-     * @example
17284-     *
17285-     * _([1, 2, 3, 4])
17286-     *  .tap(function(array) { array.pop(); })
17287-     *  .reverse()
17288-     *  .value();
17289-     * // => [3, 2, 1]
17290-     */
17291-    function tap(value, interceptor) {
17292-      interceptor(value);
17293-      return value;
17294-    }
17295-
17296-    /**
17297-     * Enables explicit method chaining on the wrapper object.
17298-     *
17299-     * @name chain
17300-     * @memberOf _
17301-     * @category Chaining
17302-     * @returns {*} Returns the wrapper object.
17303-     * @example
17304-     *
17305-     * var characters = [
17306-     *   { 'name': 'barney', 'age': 36 },
17307-     *   { 'name': 'fred',   'age': 40 }
17308-     * ];
17309-     *
17310-     * // without explicit chaining
17311-     * _(characters).first();
17312-     * // => { 'name': 'barney', 'age': 36 }
17313-     *
17314-     * // with explicit chaining
17315-     * _(characters).chain()
17316-     *   .first()
17317-     *   .pick('age')
17318-     *   .value();
17319-     * // => { 'age': 36 }
17320-     */
17321-    function wrapperChain() {
17322-      this.__chain__ = true;
17323-      return this;
17324-    }
17325-
17326-    /**
17327-     * Produces the `toString` result of the wrapped value.
17328-     *
17329-     * @name toString
17330-     * @memberOf _
17331-     * @category Chaining
17332-     * @returns {string} Returns the string result.
17333-     * @example
17334-     *
17335-     * _([1, 2, 3]).toString();
17336-     * // => '1,2,3'
17337-     */
17338-    function wrapperToString() {
17339-      return String(this.__wrapped__);
17340-    }
17341-
17342-    /**
17343-     * Extracts the wrapped value.
17344-     *
17345-     * @name valueOf
17346-     * @memberOf _
17347-     * @alias value
17348-     * @category Chaining
17349-     * @returns {*} Returns the wrapped value.
17350-     * @example
17351-     *
17352-     * _([1, 2, 3]).valueOf();
17353-     * // => [1, 2, 3]
17354-     */
17355-    function wrapperValueOf() {
17356-      return this.__wrapped__;
17357-    }
17358-
17359-    /*--------------------------------------------------------------------------*/
17360-
17361-    // add functions that return wrapped values when chaining
17362-    lodash.after = after;
17363-    lodash.assign = assign;
17364-    lodash.at = at;
17365-    lodash.bind = bind;
17366-    lodash.bindAll = bindAll;
17367-    lodash.bindKey = bindKey;
17368-    lodash.chain = chain;
17369-    lodash.compact = compact;
17370-    lodash.compose = compose;
17371-    lodash.constant = constant;
17372-    lodash.countBy = countBy;
17373-    lodash.create = create;
17374-    lodash.createCallback = createCallback;
17375-    lodash.curry = curry;
17376-    lodash.debounce = debounce;
17377-    lodash.defaults = defaults;
17378-    lodash.defer = defer;
17379-    lodash.delay = delay;
17380-    lodash.difference = difference;
17381-    lodash.filter = filter;
17382-    lodash.flatten = flatten;
17383-    lodash.forEach = forEach;
17384-    lodash.forEachRight = forEachRight;
17385-    lodash.forIn = forIn;
17386-    lodash.forInRight = forInRight;
17387-    lodash.forOwn = forOwn;
17388-    lodash.forOwnRight = forOwnRight;
17389-    lodash.functions = functions;
17390-    lodash.groupBy = groupBy;
17391-    lodash.indexBy = indexBy;
17392-    lodash.initial = initial;
17393-    lodash.intersection = intersection;
17394-    lodash.invert = invert;
17395-    lodash.invoke = invoke;
17396-    lodash.keys = keys;
17397-    lodash.map = map;
17398-    lodash.mapValues = mapValues;
17399-    lodash.max = max;
17400-    lodash.memoize = memoize;
17401-    lodash.merge = merge;
17402-    lodash.min = min;
17403-    lodash.omit = omit;
17404-    lodash.once = once;
17405-    lodash.pairs = pairs;
17406-    lodash.partial = partial;
17407-    lodash.partialRight = partialRight;
17408-    lodash.pick = pick;
17409-    lodash.pluck = pluck;
17410-    lodash.property = property;
17411-    lodash.pull = pull;
17412-    lodash.range = range;
17413-    lodash.reject = reject;
17414-    lodash.remove = remove;
17415-    lodash.rest = rest;
17416-    lodash.shuffle = shuffle;
17417-    lodash.sortBy = sortBy;
17418-    lodash.tap = tap;
17419-    lodash.throttle = throttle;
17420-    lodash.times = times;
17421-    lodash.toArray = toArray;
17422-    lodash.transform = transform;
17423-    lodash.union = union;
17424-    lodash.uniq = uniq;
17425-    lodash.values = values;
17426-    lodash.where = where;
17427-    lodash.without = without;
17428-    lodash.wrap = wrap;
17429-    lodash.xor = xor;
17430-    lodash.zip = zip;
17431-    lodash.zipObject = zipObject;
17432-
17433-    // add aliases
17434-    lodash.collect = map;
17435-    lodash.drop = rest;
17436-    lodash.each = forEach;
17437-    lodash.eachRight = forEachRight;
17438-    lodash.extend = assign;
17439-    lodash.methods = functions;
17440-    lodash.object = zipObject;
17441-    lodash.select = filter;
17442-    lodash.tail = rest;
17443-    lodash.unique = uniq;
17444-    lodash.unzip = zip;
17445-
17446-    // add functions to `lodash.prototype`
17447-    mixin(lodash);
17448-
17449-    /*--------------------------------------------------------------------------*/
17450-
17451-    // add functions that return unwrapped values when chaining
17452-    lodash.clone = clone;
17453-    lodash.cloneDeep = cloneDeep;
17454-    lodash.contains = contains;
17455-    lodash.escape = escape;
17456-    lodash.every = every;
17457-    lodash.find = find;
17458-    lodash.findIndex = findIndex;
17459-    lodash.findKey = findKey;
17460-    lodash.findLast = findLast;
17461-    lodash.findLastIndex = findLastIndex;
17462-    lodash.findLastKey = findLastKey;
17463-    lodash.has = has;
17464-    lodash.identity = identity;
17465-    lodash.indexOf = indexOf;
17466-    lodash.isArguments = isArguments;
17467-    lodash.isArray = isArray;
17468-    lodash.isBoolean = isBoolean;
17469-    lodash.isDate = isDate;
17470-    lodash.isElement = isElement;
17471-    lodash.isEmpty = isEmpty;
17472-    lodash.isEqual = isEqual;
17473-    lodash.isFinite = isFinite;
17474-    lodash.isFunction = isFunction;
17475-    lodash.isNaN = isNaN;
17476-    lodash.isNull = isNull;
17477-    lodash.isNumber = isNumber;
17478-    lodash.isObject = isObject;
17479-    lodash.isPlainObject = isPlainObject;
17480-    lodash.isRegExp = isRegExp;
17481-    lodash.isString = isString;
17482-    lodash.isUndefined = isUndefined;
17483-    lodash.lastIndexOf = lastIndexOf;
17484-    lodash.mixin = mixin;
17485-    lodash.noConflict = noConflict;
17486-    lodash.noop = noop;
17487-    lodash.now = now;
17488-    lodash.parseInt = parseInt;
17489-    lodash.random = random;
17490-    lodash.reduce = reduce;
17491-    lodash.reduceRight = reduceRight;
17492-    lodash.result = result;
17493-    lodash.runInContext = runInContext;
17494-    lodash.size = size;
17495-    lodash.some = some;
17496-    lodash.sortedIndex = sortedIndex;
17497-    lodash.template = template;
17498-    lodash.unescape = unescape;
17499-    lodash.uniqueId = uniqueId;
17500-
17501-    // add aliases
17502-    lodash.all = every;
17503-    lodash.any = some;
17504-    lodash.detect = find;
17505-    lodash.findWhere = find;
17506-    lodash.foldl = reduce;
17507-    lodash.foldr = reduceRight;
17508-    lodash.include = contains;
17509-    lodash.inject = reduce;
17510-
17511-    mixin(function() {
17512-      var source = {}
17513-      forOwn(lodash, function(func, methodName) {
17514-        if (!lodash.prototype[methodName]) {
17515-          source[methodName] = func;
17516-        }
17517-      });
17518-      return source;
17519-    }(), false);
17520-
17521-    /*--------------------------------------------------------------------------*/
17522-
17523-    // add functions capable of returning wrapped and unwrapped values when chaining
17524-    lodash.first = first;
17525-    lodash.last = last;
17526-    lodash.sample = sample;
17527-
17528-    // add aliases
17529-    lodash.take = first;
17530-    lodash.head = first;
17531-
17532-    forOwn(lodash, function(func, methodName) {
17533-      var callbackable = methodName !== 'sample';
17534-      if (!lodash.prototype[methodName]) {
17535-        lodash.prototype[methodName]= function(n, guard) {
17536-          var chainAll = this.__chain__,
17537-            result = func(this.__wrapped__, n, guard);
17538-
17539-          return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
17540-            ? result
17541-            : new lodashWrapper(result, chainAll);
17542-        };
17543-      }
17544-    });
17545-
17546-    /*--------------------------------------------------------------------------*/
17547-
17548-    /**
17549-     * The semantic version number.
17550-     *
17551-     * @static
17552-     * @memberOf _
17553-     * @type string
17554-     */
17555-    lodash.VERSION = '2.4.1';
17556-
17557-    // add "Chaining" functions to the wrapper
17558-    lodash.prototype.chain = wrapperChain;
17559-    lodash.prototype.toString = wrapperToString;
17560-    lodash.prototype.value = wrapperValueOf;
17561-    lodash.prototype.valueOf = wrapperValueOf;
17562-
17563-    // add `Array` functions that return unwrapped values
17564-    forEach(['join', 'pop', 'shift'], function(methodName) {
17565-      var func = arrayRef[methodName];
17566-      lodash.prototype[methodName] = function() {
17567-        var chainAll = this.__chain__,
17568-          result = func.apply(this.__wrapped__, arguments);
17569-
17570-        return chainAll
17571-          ? new lodashWrapper(result, chainAll)
17572-          : result;
17573-      };
17574-    });
17575-
17576-    // add `Array` functions that return the existing wrapped value
17577-    forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
17578-      var func = arrayRef[methodName];
17579-      lodash.prototype[methodName] = function() {
17580-        func.apply(this.__wrapped__, arguments);
17581-        return this;
17582-      };
17583-    });
17584-
17585-    // add `Array` functions that return new wrapped values
17586-    forEach(['concat', 'slice', 'splice'], function(methodName) {
17587-      var func = arrayRef[methodName];
17588-      lodash.prototype[methodName] = function() {
17589-        return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
17590-      };
17591-    });
17592-
17593-    return lodash;
17594-  }
17595-
17596-  /*--------------------------------------------------------------------------*/
17597-
17598-  // expose Lo-Dash
17599-  var _ = runInContext();
17600-  // some AMD build optimizers like r.js check for condition patterns like the following:
17601-  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
17602-    // Expose Lo-Dash to the global object even when an AMD loader is present in
17603-    // case Lo-Dash is loaded with a RequireJS shim config.
17604-    // See http://requirejs.org/docs/api.html#config-shim
17605-    root._ = _;
17606-
17607-    // define as an anonymous module so, through path mapping, it can be
17608-    // referenced as the "underscore" module
17609-    define(function() {
17610-      return _;
17611-    });
17612-  }
17613-  // check for `exports` after `define` in case a build optimizer adds an `exports` object
17614-  else if (freeExports && freeModule) {
17615-    // in Node.js or RingoJS
17616-    if (moduleExports) {
17617-      (freeModule.exports = _)._ = _;
17618-    }
17619-    // in Narwhal or Rhino -require
17620-    else {
17621-      freeExports._ = _;
17622-    }
17623-  }
17624-  else {
17625-    // in a browser or Rhino
17626-    //root._ = _;
17627-    //return _;
17628-
17629-    root._ = root._ || {};
17630-    root._ = _;
17631-    return root._;
17632-  }
17633-}.call(this));
17634diff --git a/lib/moment/moment.js b/lib/moment/moment.js
17635deleted file mode 100644
17636index 1af2292..0000000
17637--- a/lib/moment/moment.js
17638+++ /dev/null
17639@@ -1,2363 +0,0 @@
17640-//! moment.js
17641-//! version : 2.5.0
17642-//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
17643-//! license : MIT
17644-//! momentjs.com
17645-
17646-(function (undefined) {
17647-
17648-  /************************************
17649-   Constants
17650-   ************************************/
17651-
17652-  var moment,
17653-    VERSION = "2.5.0",
17654-    global = this,
17655-    round = Math.round,
17656-    i,
17657-
17658-    YEAR = 0,
17659-    MONTH = 1,
17660-    DATE = 2,
17661-    HOUR = 3,
17662-    MINUTE = 4,
17663-    SECOND = 5,
17664-    MILLISECOND = 6,
17665-
17666-    // internal storage for language config files
17667-    languages = {},
17668-
17669-    // check for nodeJS
17670-    hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'),
17671-
17672-    // ASP.NET json date format regex
17673-    aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
17674-    aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
17675-
17676-    // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
17677-    // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
17678-    isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
17679-
17680-    // format tokens
17681-    formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,
17682-    localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
17683-
17684-    // parsing token regexes
17685-    parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
17686-    parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
17687-    parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
17688-    parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
17689-    parseTokenDigits = /\d+/, // nonzero number of digits
17690-    parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
17691-    parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
17692-    parseTokenT = /T/i, // T (ISO separator)
17693-    parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
17694-
17695-    //strict parsing regexes
17696-    parseTokenOneDigit = /\d/, // 0 - 9
17697-    parseTokenTwoDigits = /\d\d/, // 00 - 99
17698-    parseTokenThreeDigits = /\d{3}/, // 000 - 999
17699-    parseTokenFourDigits = /\d{4}/, // 0000 - 9999
17700-    parseTokenSixDigits = /[+\-]?\d{6}/, // -999,999 - 999,999
17701-
17702-    // iso 8601 regex
17703-    // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
17704-    isoRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
17705-
17706-    isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
17707-
17708-    isoDates = [
17709-      'YYYY-MM-DD',
17710-      'GGGG-[W]WW',
17711-      'GGGG-[W]WW-E',
17712-      'YYYY-DDD'
17713-    ],
17714-
17715-    // iso time formats and regexes
17716-    isoTimes = [
17717-      ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/],
17718-      ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
17719-      ['HH:mm', /(T| )\d\d:\d\d/],
17720-      ['HH', /(T| )\d\d/]
17721-    ],
17722-
17723-    // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
17724-    parseTimezoneChunker = /([\+\-]|\d\d)/gi,
17725-
17726-    // getter and setter names
17727-    proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
17728-    unitMillisecondFactors = {
17729-      'Milliseconds' : 1,
17730-      'Seconds' : 1e3,
17731-      'Minutes' : 6e4,
17732-      'Hours' : 36e5,
17733-      'Days' : 864e5,
17734-      'Months' : 2592e6,
17735-      'Years' : 31536e6
17736-    },
17737-
17738-    unitAliases = {
17739-      ms : 'millisecond',
17740-      s : 'second',
17741-      m : 'minute',
17742-      h : 'hour',
17743-      d : 'day',
17744-      D : 'date',
17745-      w : 'week',
17746-      W : 'isoWeek',
17747-      M : 'month',
17748-      y : 'year',
17749-      DDD : 'dayOfYear',
17750-      e : 'weekday',
17751-      E : 'isoWeekday',
17752-      gg: 'weekYear',
17753-      GG: 'isoWeekYear'
17754-    },
17755-
17756-    camelFunctions = {
17757-      dayofyear : 'dayOfYear',
17758-      isoweekday : 'isoWeekday',
17759-      isoweek : 'isoWeek',
17760-      weekyear : 'weekYear',
17761-      isoweekyear : 'isoWeekYear'
17762-    },
17763-
17764-    // format function strings
17765-    formatFunctions = {},
17766-
17767-    // tokens to ordinalize and pad
17768-    ordinalizeTokens = 'DDD w W M D d'.split(' '),
17769-    paddedTokens = 'M D H h m s w W'.split(' '),
17770-
17771-    formatTokenFunctions = {
17772-      M    : function () {
17773-        return this.month() + 1;
17774-      },
17775-      MMM  : function (format) {
17776-        return this.lang().monthsShort(this, format);
17777-      },
17778-      MMMM : function (format) {
17779-        return this.lang().months(this, format);
17780-      },
17781-      D    : function () {
17782-        return this.date();
17783-      },
17784-      DDD  : function () {
17785-        return this.dayOfYear();
17786-      },
17787-      d    : function () {
17788-        return this.day();
17789-      },
17790-      dd   : function (format) {
17791-        return this.lang().weekdaysMin(this, format);
17792-      },
17793-      ddd  : function (format) {
17794-        return this.lang().weekdaysShort(this, format);
17795-      },
17796-      dddd : function (format) {
17797-        return this.lang().weekdays(this, format);
17798-      },
17799-      w    : function () {
17800-        return this.week();
17801-      },
17802-      W    : function () {
17803-        return this.isoWeek();
17804-      },
17805-      YY   : function () {
17806-        return leftZeroFill(this.year() % 100, 2);
17807-      },
17808-      YYYY : function () {
17809-        return leftZeroFill(this.year(), 4);
17810-      },
17811-      YYYYY : function () {
17812-        return leftZeroFill(this.year(), 5);
17813-      },
17814-      YYYYYY : function () {
17815-        var y = this.year(), sign = y >= 0 ? '+' : '-';
17816-        return sign + leftZeroFill(Math.abs(y), 6);
17817-      },
17818-      gg   : function () {
17819-        return leftZeroFill(this.weekYear() % 100, 2);
17820-      },
17821-      gggg : function () {
17822-        return this.weekYear();
17823-      },
17824-      ggggg : function () {
17825-        return leftZeroFill(this.weekYear(), 5);
17826-      },
17827-      GG   : function () {
17828-        return leftZeroFill(this.isoWeekYear() % 100, 2);
17829-      },
17830-      GGGG : function () {
17831-        return this.isoWeekYear();
17832-      },
17833-      GGGGG : function () {
17834-        return leftZeroFill(this.isoWeekYear(), 5);
17835-      },
17836-      e : function () {
17837-        return this.weekday();
17838-      },
17839-      E : function () {
17840-        return this.isoWeekday();
17841-      },
17842-      a    : function () {
17843-        return this.lang().meridiem(this.hours(), this.minutes(), true);
17844-      },
17845-      A    : function () {
17846-        return this.lang().meridiem(this.hours(), this.minutes(), false);
17847-      },
17848-      H    : function () {
17849-        return this.hours();
17850-      },
17851-      h    : function () {
17852-        return this.hours() % 12 || 12;
17853-      },
17854-      m    : function () {
17855-        return this.minutes();
17856-      },
17857-      s    : function () {
17858-        return this.seconds();
17859-      },
17860-      S    : function () {
17861-        return toInt(this.milliseconds() / 100);
17862-      },
17863-      SS   : function () {
17864-        return leftZeroFill(toInt(this.milliseconds() / 10), 2);
17865-      },
17866-      SSS  : function () {
17867-        return leftZeroFill(this.milliseconds(), 3);
17868-      },
17869-      SSSS : function () {
17870-        return leftZeroFill(this.milliseconds(), 3);
17871-      },
17872-      Z    : function () {
17873-        var a = -this.zone(),
17874-          b = "+";
17875-        if (a < 0) {
17876-          a = -a;
17877-          b = "-";
17878-        }
17879-        return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2);
17880-      },
17881-      ZZ   : function () {
17882-        var a = -this.zone(),
17883-          b = "+";
17884-        if (a < 0) {
17885-          a = -a;
17886-          b = "-";
17887-        }
17888-        return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
17889-      },
17890-      z : function () {
17891-        return this.zoneAbbr();
17892-      },
17893-      zz : function () {
17894-        return this.zoneName();
17895-      },
17896-      X    : function () {
17897-        return this.unix();
17898-      },
17899-      Q : function () {
17900-        return this.quarter();
17901-      }
17902-    },
17903-
17904-    lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'];
17905-
17906-  function padToken(func, count) {
17907-    return function (a) {
17908-      return leftZeroFill(func.call(this, a), count);
17909-    };
17910-  }
17911-  function ordinalizeToken(func, period) {
17912-    return function (a) {
17913-      return this.lang().ordinal(func.call(this, a), period);
17914-    };
17915-  }
17916-
17917-  while (ordinalizeTokens.length) {
17918-    i = ordinalizeTokens.pop();
17919-    formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
17920-  }
17921-  while (paddedTokens.length) {
17922-    i = paddedTokens.pop();
17923-    formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
17924-  }
17925-  formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
17926-
17927-
17928-  /************************************
17929-   Constructors
17930-   ************************************/
17931-
17932-  function Language() {
17933-
17934-  }
17935-
17936-  // Moment prototype object
17937-  function Moment(config) {
17938-    checkOverflow(config);
17939-    extend(this, config);
17940-  }
17941-
17942-  // Duration Constructor
17943-  function Duration(duration) {
17944-    var normalizedInput = normalizeObjectUnits(duration),
17945-      years = normalizedInput.year || 0,
17946-      months = normalizedInput.month || 0,
17947-      weeks = normalizedInput.week || 0,
17948-      days = normalizedInput.day || 0,
17949-      hours = normalizedInput.hour || 0,
17950-      minutes = normalizedInput.minute || 0,
17951-      seconds = normalizedInput.second || 0,
17952-      milliseconds = normalizedInput.millisecond || 0;
17953-
17954-    // representation for dateAddRemove
17955-    this._milliseconds = +milliseconds +
17956-      seconds * 1e3 + // 1000
17957-      minutes * 6e4 + // 1000 * 60
17958-      hours * 36e5; // 1000 * 60 * 60
17959-    // Because of dateAddRemove treats 24 hours as different from a
17960-    // day when working around DST, we need to store them separately
17961-    this._days = +days +
17962-      weeks * 7;
17963-    // It is impossible translate months into days without knowing
17964-    // which months you are are talking about, so we have to store
17965-    // it separately.
17966-    this._months = +months +
17967-      years * 12;
17968-
17969-    this._data = {};
17970-
17971-    this._bubble();
17972-  }
17973-
17974-  /************************************
17975-   Helpers
17976-   ************************************/
17977-
17978-
17979-  function extend(a, b) {
17980-    for (var i in b) {
17981-      if (b.hasOwnProperty(i)) {
17982-        a[i] = b[i];
17983-      }
17984-    }
17985-
17986-    if (b.hasOwnProperty("toString")) {
17987-      a.toString = b.toString;
17988-    }
17989-
17990-    if (b.hasOwnProperty("valueOf")) {
17991-      a.valueOf = b.valueOf;
17992-    }
17993-
17994-    return a;
17995-  }
17996-
17997-  function absRound(number) {
17998-    if (number < 0) {
17999-      return Math.ceil(number);
18000-    } else {
18001-      return Math.floor(number);
18002-    }
18003-  }
18004-
18005-  // left zero fill a number
18006-  // see http://jsperf.com/left-zero-filling for performance comparison
18007-  function leftZeroFill(number, targetLength, forceSign) {
18008-    var output = Math.abs(number) + '',
18009-      sign = number >= 0;
18010-
18011-    while (output.length < targetLength) {
18012-      output = '0' + output;
18013-    }
18014-    return (sign ? (forceSign ? '+' : '') : '-') + output;
18015-  }
18016-
18017-  // helper function for _.addTime and _.subtractTime
18018-  function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) {
18019-    var milliseconds = duration._milliseconds,
18020-      days = duration._days,
18021-      months = duration._months,
18022-      minutes,
18023-      hours;
18024-
18025-    if (milliseconds) {
18026-      mom._d.setTime(+mom._d + milliseconds * isAdding);
18027-    }
18028-    // store the minutes and hours so we can restore them
18029-    if (days || months) {
18030-      minutes = mom.minute();
18031-      hours = mom.hour();
18032-    }
18033-    if (days) {
18034-      mom.date(mom.date() + days * isAdding);
18035-    }
18036-    if (months) {
18037-      mom.month(mom.month() + months * isAdding);
18038-    }
18039-    if (milliseconds && !ignoreUpdateOffset) {
18040-      moment.updateOffset(mom);
18041-    }
18042-    // restore the minutes and hours after possibly changing dst
18043-    if (days || months) {
18044-      mom.minute(minutes);
18045-      mom.hour(hours);
18046-    }
18047-  }
18048-
18049-  // check if is an array
18050-  function isArray(input) {
18051-    return Object.prototype.toString.call(input) === '[object Array]';
18052-  }
18053-
18054-  function isDate(input) {
18055-    return  Object.prototype.toString.call(input) === '[object Date]' ||
18056-      input instanceof Date;
18057-  }
18058-
18059-  // compare two arrays, return the number of differences
18060-  function compareArrays(array1, array2, dontConvert) {
18061-    var len = Math.min(array1.length, array2.length),
18062-      lengthDiff = Math.abs(array1.length - array2.length),
18063-      diffs = 0,
18064-      i;
18065-    for (i = 0; i < len; i++) {
18066-      if ((dontConvert && array1[i] !== array2[i]) ||
18067-        (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
18068-        diffs++;
18069-      }
18070-    }
18071-    return diffs + lengthDiff;
18072-  }
18073-
18074-  function normalizeUnits(units) {
18075-    if (units) {
18076-      var lowered = units.toLowerCase().replace(/(.)s$/, '$1');
18077-      units = unitAliases[units] || camelFunctions[lowered] || lowered;
18078-    }
18079-    return units;
18080-  }
18081-
18082-  function normalizeObjectUnits(inputObject) {
18083-    var normalizedInput = {},
18084-      normalizedProp,
18085-      prop;
18086-
18087-    for (prop in inputObject) {
18088-      if (inputObject.hasOwnProperty(prop)) {
18089-        normalizedProp = normalizeUnits(prop);
18090-        if (normalizedProp) {
18091-          normalizedInput[normalizedProp] = inputObject[prop];
18092-        }
18093-      }
18094-    }
18095-
18096-    return normalizedInput;
18097-  }
18098-
18099-  function makeList(field) {
18100-    var count, setter;
18101-
18102-    if (field.indexOf('week') === 0) {
18103-      count = 7;
18104-      setter = 'day';
18105-    }
18106-    else if (field.indexOf('month') === 0) {
18107-      count = 12;
18108-      setter = 'month';
18109-    }
18110-    else {
18111-      return;
18112-    }
18113-
18114-    moment[field] = function (format, index) {
18115-      var i, getter,
18116-        method = moment.fn._lang[field],
18117-        results = [];
18118-
18119-      if (typeof format === 'number') {
18120-        index = format;
18121-        format = undefined;
18122-      }
18123-
18124-      getter = function (i) {
18125-        var m = moment().utc().set(setter, i);
18126-        return method.call(moment.fn._lang, m, format || '');
18127-      };
18128-
18129-      if (index != null) {
18130-        return getter(index);
18131-      }
18132-      else {
18133-        for (i = 0; i < count; i++) {
18134-          results.push(getter(i));
18135-        }
18136-        return results;
18137-      }
18138-    };
18139-  }
18140-
18141-  function toInt(argumentForCoercion) {
18142-    var coercedNumber = +argumentForCoercion,
18143-      value = 0;
18144-
18145-    if (coercedNumber !== 0 && isFinite(coercedNumber)) {
18146-      if (coercedNumber >= 0) {
18147-        value = Math.floor(coercedNumber);
18148-      } else {
18149-        value = Math.ceil(coercedNumber);
18150-      }
18151-    }
18152-
18153-    return value;
18154-  }
18155-
18156-  function daysInMonth(year, month) {
18157-    return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
18158-  }
18159-
18160-  function daysInYear(year) {
18161-    return isLeapYear(year) ? 366 : 365;
18162-  }
18163-
18164-  function isLeapYear(year) {
18165-    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
18166-  }
18167-
18168-  function checkOverflow(m) {
18169-    var overflow;
18170-    if (m._a && m._pf.overflow === -2) {
18171-      overflow =
18172-        m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
18173-          m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
18174-            m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR :
18175-              m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
18176-                m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
18177-                  m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
18178-                    -1;
18179-
18180-      if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
18181-        overflow = DATE;
18182-      }
18183-
18184-      m._pf.overflow = overflow;
18185-    }
18186-  }
18187-
18188-  function initializeParsingFlags(config) {
18189-    config._pf = {
18190-      empty : false,
18191-      unusedTokens : [],
18192-      unusedInput : [],
18193-      overflow : -2,
18194-      charsLeftOver : 0,
18195-      nullInput : false,
18196-      invalidMonth : null,
18197-      invalidFormat : false,
18198-      userInvalidated : false,
18199-      iso: false
18200-    };
18201-  }
18202-
18203-  function isValid(m) {
18204-    if (m._isValid == null) {
18205-      m._isValid = !isNaN(m._d.getTime()) &&
18206-        m._pf.overflow < 0 &&
18207-        !m._pf.empty &&
18208-        !m._pf.invalidMonth &&
18209-        !m._pf.nullInput &&
18210-        !m._pf.invalidFormat &&
18211-        !m._pf.userInvalidated;
18212-
18213-      if (m._strict) {
18214-        m._isValid = m._isValid &&
18215-          m._pf.charsLeftOver === 0 &&
18216-          m._pf.unusedTokens.length === 0;
18217-      }
18218-    }
18219-    return m._isValid;
18220-  }
18221-
18222-  function normalizeLanguage(key) {
18223-    return key ? key.toLowerCase().replace('_', '-') : key;
18224-  }
18225-
18226-  // Return a moment from input, that is local/utc/zone equivalent to model.
18227-  function makeAs(input, model) {
18228-    return model._isUTC ? moment(input).zone(model._offset || 0) :
18229-      moment(input).local();
18230-  }
18231-
18232-  /************************************
18233-   Languages
18234-   ************************************/
18235-
18236-
18237-  extend(Language.prototype, {
18238-
18239-    set : function (config) {
18240-      var prop, i;
18241-      for (i in config) {
18242-        prop = config[i];
18243-        if (typeof prop === 'function') {
18244-          this[i] = prop;
18245-        } else {
18246-          this['_' + i] = prop;
18247-        }
18248-      }
18249-    },
18250-
18251-    _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
18252-    months : function (m) {
18253-      return this._months[m.month()];
18254-    },
18255-
18256-    _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
18257-    monthsShort : function (m) {
18258-      return this._monthsShort[m.month()];
18259-    },
18260-
18261-    monthsParse : function (monthName) {
18262-      var i, mom, regex;
18263-
18264-      if (!this._monthsParse) {
18265-        this._monthsParse = [];
18266-      }
18267-
18268-      for (i = 0; i < 12; i++) {
18269-        // make the regex if we don't have it already
18270-        if (!this._monthsParse[i]) {
18271-          mom = moment.utc([2000, i]);
18272-          regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
18273-          this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
18274-        }
18275-        // test the regex
18276-        if (this._monthsParse[i].test(monthName)) {
18277-          return i;
18278-        }
18279-      }
18280-    },
18281-
18282-    _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
18283-    weekdays : function (m) {
18284-      return this._weekdays[m.day()];
18285-    },
18286-
18287-    _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
18288-    weekdaysShort : function (m) {
18289-      return this._weekdaysShort[m.day()];
18290-    },
18291-
18292-    _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
18293-    weekdaysMin : function (m) {
18294-      return this._weekdaysMin[m.day()];
18295-    },
18296-
18297-    weekdaysParse : function (weekdayName) {
18298-      var i, mom, regex;
18299-
18300-      if (!this._weekdaysParse) {
18301-        this._weekdaysParse = [];
18302-      }
18303-
18304-      for (i = 0; i < 7; i++) {
18305-        // make the regex if we don't have it already
18306-        if (!this._weekdaysParse[i]) {
18307-          mom = moment([2000, 1]).day(i);
18308-          regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
18309-          this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
18310-        }
18311-        // test the regex
18312-        if (this._weekdaysParse[i].test(weekdayName)) {
18313-          return i;
18314-        }
18315-      }
18316-    },
18317-
18318-    _longDateFormat : {
18319-      LT : "h:mm A",
18320-      L : "MM/DD/YYYY",
18321-      LL : "MMMM D YYYY",
18322-      LLL : "MMMM D YYYY LT",
18323-      LLLL : "dddd, MMMM D YYYY LT"
18324-    },
18325-    longDateFormat : function (key) {
18326-      var output = this._longDateFormat[key];
18327-      if (!output && this._longDateFormat[key.toUpperCase()]) {
18328-        output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
18329-          return val.slice(1);
18330-        });
18331-        this._longDateFormat[key] = output;
18332-      }
18333-      return output;
18334-    },
18335-
18336-    isPM : function (input) {
18337-      // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
18338-      // Using charAt should be more compatible.
18339-      return ((input + '').toLowerCase().charAt(0) === 'p');
18340-    },
18341-
18342-    _meridiemParse : /[ap]\.?m?\.?/i,
18343-    meridiem : function (hours, minutes, isLower) {
18344-      if (hours > 11) {
18345-        return isLower ? 'pm' : 'PM';
18346-      } else {
18347-        return isLower ? 'am' : 'AM';
18348-      }
18349-    },
18350-
18351-    _calendar : {
18352-      sameDay : '[Today at] LT',
18353-      nextDay : '[Tomorrow at] LT',
18354-      nextWeek : 'dddd [at] LT',
18355-      lastDay : '[Yesterday at] LT',
18356-      lastWeek : '[Last] dddd [at] LT',
18357-      sameElse : 'L'
18358-    },
18359-    calendar : function (key, mom) {
18360-      var output = this._calendar[key];
18361-      return typeof output === 'function' ? output.apply(mom) : output;
18362-    },
18363-
18364-    _relativeTime : {
18365-      future : "in %s",
18366-      past : "%s ago",
18367-      s : "a few seconds",
18368-      m : "a minute",
18369-      mm : "%d minutes",
18370-      h : "an hour",
18371-      hh : "%d hours",
18372-      d : "a day",
18373-      dd : "%d days",
18374-      M : "a month",
18375-      MM : "%d months",
18376-      y : "a year",
18377-      yy : "%d years"
18378-    },
18379-    relativeTime : function (number, withoutSuffix, string, isFuture) {
18380-      var output = this._relativeTime[string];
18381-      return (typeof output === 'function') ?
18382-        output(number, withoutSuffix, string, isFuture) :
18383-        output.replace(/%d/i, number);
18384-    },
18385-    pastFuture : function (diff, output) {
18386-      var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
18387-      return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
18388-    },
18389-
18390-    ordinal : function (number) {
18391-      return this._ordinal.replace("%d", number);
18392-    },
18393-    _ordinal : "%d",
18394-
18395-    preparse : function (string) {
18396-      return string;
18397-    },
18398-
18399-    postformat : function (string) {
18400-      return string;
18401-    },
18402-
18403-    week : function (mom) {
18404-      return weekOfYear(mom, this._week.dow, this._week.doy).week;
18405-    },
18406-
18407-    _week : {
18408-      dow : 0, // Sunday is the first day of the week.
18409-      doy : 6  // The week that contains Jan 1st is the first week of the year.
18410-    },
18411-
18412-    _invalidDate: 'Invalid date',
18413-    invalidDate: function () {
18414-      return this._invalidDate;
18415-    }
18416-  });
18417-
18418-  // Loads a language definition into the `languages` cache.  The function
18419-  // takes a key and optionally values.  If not in the browser and no values
18420-  // are provided, it will load the language file module.  As a convenience,
18421-  // this function also returns the language values.
18422-  function loadLang(key, values) {
18423-    values.abbr = key;
18424-    if (!languages[key]) {
18425-      languages[key] = new Language();
18426-    }
18427-    languages[key].set(values);
18428-    return languages[key];
18429-  }
18430-
18431-  // Remove a language from the `languages` cache. Mostly useful in tests.
18432-  function unloadLang(key) {
18433-    delete languages[key];
18434-  }
18435-
18436-  // Determines which language definition to use and returns it.
18437-  //
18438-  // With no parameters, it will return the global language.  If you
18439-  // pass in a language key, such as 'en', it will return the
18440-  // definition for 'en', so long as 'en' has already been loaded using
18441-  // moment.lang.
18442-  function getLangDefinition(key) {
18443-    var i = 0, j, lang, next, split,
18444-      get = function (k) {
18445-        if (!languages[k] && hasModule) {
18446-          try {
18447-            require('./lang/' + k);
18448-          } catch (e) { }
18449-        }
18450-        return languages[k];
18451-      };
18452-
18453-    if (!key) {
18454-      return moment.fn._lang;
18455-    }
18456-
18457-    if (!isArray(key)) {
18458-      //short-circuit everything else
18459-      lang = get(key);
18460-      if (lang) {
18461-        return lang;
18462-      }
18463-      key = [key];
18464-    }
18465-
18466-    //pick the language from the array
18467-    //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
18468-    //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
18469-    while (i < key.length) {
18470-      split = normalizeLanguage(key[i]).split('-');
18471-      j = split.length;
18472-      next = normalizeLanguage(key[i + 1]);
18473-      next = next ? next.split('-') : null;
18474-      while (j > 0) {
18475-        lang = get(split.slice(0, j).join('-'));
18476-        if (lang) {
18477-          return lang;
18478-        }
18479-        if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
18480-          //the next array item is better than a shallower substring of this one
18481-          break;
18482-        }
18483-        j--;
18484-      }
18485-      i++;
18486-    }
18487-    return moment.fn._lang;
18488-  }
18489-
18490-  /************************************
18491-   Formatting
18492-   ************************************/
18493-
18494-
18495-  function removeFormattingTokens(input) {
18496-    if (input.match(/\[[\s\S]/)) {
18497-      return input.replace(/^\[|\]$/g, "");
18498-    }
18499-    return input.replace(/\\/g, "");
18500-  }
18501-
18502-  function makeFormatFunction(format) {
18503-    var array = format.match(formattingTokens), i, length;
18504-
18505-    for (i = 0, length = array.length; i < length; i++) {
18506-      if (formatTokenFunctions[array[i]]) {
18507-        array[i] = formatTokenFunctions[array[i]];
18508-      } else {
18509-        array[i] = removeFormattingTokens(array[i]);
18510-      }
18511-    }
18512-
18513-    return function (mom) {
18514-      var output = "";
18515-      for (i = 0; i < length; i++) {
18516-        output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
18517-      }
18518-      return output;
18519-    };
18520-  }
18521-
18522-  // format date using native date object
18523-  function formatMoment(m, format) {
18524-
18525-    if (!m.isValid()) {
18526-      return m.lang().invalidDate();
18527-    }
18528-
18529-    format = expandFormat(format, m.lang());
18530-
18531-    if (!formatFunctions[format]) {
18532-      formatFunctions[format] = makeFormatFunction(format);
18533-    }
18534-
18535-    return formatFunctions[format](m);
18536-  }
18537-
18538-  function expandFormat(format, lang) {
18539-    var i = 5;
18540-
18541-    function replaceLongDateFormatTokens(input) {
18542-      return lang.longDateFormat(input) || input;
18543-    }
18544-
18545-    localFormattingTokens.lastIndex = 0;
18546-    while (i >= 0 && localFormattingTokens.test(format)) {
18547-      format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
18548-      localFormattingTokens.lastIndex = 0;
18549-      i -= 1;
18550-    }
18551-
18552-    return format;
18553-  }
18554-
18555-
18556-  /************************************
18557-   Parsing
18558-   ************************************/
18559-
18560-
18561-  // get the regex to find the next token
18562-  function getParseRegexForToken(token, config) {
18563-    var a, strict = config._strict;
18564-    switch (token) {
18565-      case 'DDDD':
18566-        return parseTokenThreeDigits;
18567-      case 'YYYY':
18568-      case 'GGGG':
18569-      case 'gggg':
18570-        return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
18571-      case 'YYYYYY':
18572-      case 'YYYYY':
18573-      case 'GGGGG':
18574-      case 'ggggg':
18575-        return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
18576-      case 'S':
18577-        if (strict) { return parseTokenOneDigit; }
18578-      /* falls through */
18579-      case 'SS':
18580-        if (strict) { return parseTokenTwoDigits; }
18581-      /* falls through */
18582-      case 'SSS':
18583-      case 'DDD':
18584-        return strict ? parseTokenThreeDigits : parseTokenOneToThreeDigits;
18585-      case 'MMM':
18586-      case 'MMMM':
18587-      case 'dd':
18588-      case 'ddd':
18589-      case 'dddd':
18590-        return parseTokenWord;
18591-      case 'a':
18592-      case 'A':
18593-        return getLangDefinition(config._l)._meridiemParse;
18594-      case 'X':
18595-        return parseTokenTimestampMs;
18596-      case 'Z':
18597-      case 'ZZ':
18598-        return parseTokenTimezone;
18599-      case 'T':
18600-        return parseTokenT;
18601-      case 'SSSS':
18602-        return parseTokenDigits;
18603-      case 'MM':
18604-      case 'DD':
18605-      case 'YY':
18606-      case 'GG':
18607-      case 'gg':
18608-      case 'HH':
18609-      case 'hh':
18610-      case 'mm':
18611-      case 'ss':
18612-      case 'ww':
18613-      case 'WW':
18614-        return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
18615-      case 'M':
18616-      case 'D':
18617-      case 'd':
18618-      case 'H':
18619-      case 'h':
18620-      case 'm':
18621-      case 's':
18622-      case 'w':
18623-      case 'W':
18624-      case 'e':
18625-      case 'E':
18626-        return strict ? parseTokenOneDigit : parseTokenOneOrTwoDigits;
18627-      default :
18628-        a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i"));
18629-        return a;
18630-    }
18631-  }
18632-
18633-  function timezoneMinutesFromString(string) {
18634-    string = string || "";
18635-    var possibleTzMatches = (string.match(parseTokenTimezone) || []),
18636-      tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
18637-      parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
18638-      minutes = +(parts[1] * 60) + toInt(parts[2]);
18639-
18640-    return parts[0] === '+' ? -minutes : minutes;
18641-  }
18642-
18643-  // function to convert string input to date
18644-  function addTimeToArrayFromToken(token, input, config) {
18645-    var a, datePartArray = config._a;
18646-
18647-    switch (token) {
18648-      // MONTH
18649-      case 'M' : // fall through to MM
18650-      case 'MM' :
18651-        if (input != null) {
18652-          datePartArray[MONTH] = toInt(input) - 1;
18653-        }
18654-        break;
18655-      case 'MMM' : // fall through to MMMM
18656-      case 'MMMM' :
18657-        a = getLangDefinition(config._l).monthsParse(input);
18658-        // if we didn't find a month name, mark the date as invalid.
18659-        if (a != null) {
18660-          datePartArray[MONTH] = a;
18661-        } else {
18662-          config._pf.invalidMonth = input;
18663-        }
18664-        break;
18665-      // DAY OF MONTH
18666-      case 'D' : // fall through to DD
18667-      case 'DD' :
18668-        if (input != null) {
18669-          datePartArray[DATE] = toInt(input);
18670-        }
18671-        break;
18672-      // DAY OF YEAR
18673-      case 'DDD' : // fall through to DDDD
18674-      case 'DDDD' :
18675-        if (input != null) {
18676-          config._dayOfYear = toInt(input);
18677-        }
18678-
18679-        break;
18680-      // YEAR
18681-      case 'YY' :
18682-        datePartArray[YEAR] = toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
18683-        break;
18684-      case 'YYYY' :
18685-      case 'YYYYY' :
18686-      case 'YYYYYY' :
18687-        datePartArray[YEAR] = toInt(input);
18688-        break;
18689-      // AM / PM
18690-      case 'a' : // fall through to A
18691-      case 'A' :
18692-        config._isPm = getLangDefinition(config._l).isPM(input);
18693-        break;
18694-      // 24 HOUR
18695-      case 'H' : // fall through to hh
18696-      case 'HH' : // fall through to hh
18697-      case 'h' : // fall through to hh
18698-      case 'hh' :
18699-        datePartArray[HOUR] = toInt(input);
18700-        break;
18701-      // MINUTE
18702-      case 'm' : // fall through to mm
18703-      case 'mm' :
18704-        datePartArray[MINUTE] = toInt(input);
18705-        break;
18706-      // SECOND
18707-      case 's' : // fall through to ss
18708-      case 'ss' :
18709-        datePartArray[SECOND] = toInt(input);
18710-        break;
18711-      // MILLISECOND
18712-      case 'S' :
18713-      case 'SS' :
18714-      case 'SSS' :
18715-      case 'SSSS' :
18716-        datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
18717-        break;
18718-      // UNIX TIMESTAMP WITH MS
18719-      case 'X':
18720-        config._d = new Date(parseFloat(input) * 1000);
18721-        break;
18722-      // TIMEZONE
18723-      case 'Z' : // fall through to ZZ
18724-      case 'ZZ' :
18725-        config._useUTC = true;
18726-        config._tzm = timezoneMinutesFromString(input);
18727-        break;
18728-      case 'w':
18729-      case 'ww':
18730-      case 'W':
18731-      case 'WW':
18732-      case 'd':
18733-      case 'dd':
18734-      case 'ddd':
18735-      case 'dddd':
18736-      case 'e':
18737-      case 'E':
18738-        token = token.substr(0, 1);
18739-      /* falls through */
18740-      case 'gg':
18741-      case 'gggg':
18742-      case 'GG':
18743-      case 'GGGG':
18744-      case 'GGGGG':
18745-        token = token.substr(0, 2);
18746-        if (input) {
18747-          config._w = config._w || {};
18748-          config._w[token] = input;
18749-        }
18750-        break;
18751-    }
18752-  }
18753-
18754-  // convert an array to a date.
18755-  // the array should mirror the parameters below
18756-  // note: all values past the year are optional and will default to the lowest possible value.
18757-  // [year, month, day , hour, minute, second, millisecond]
18758-  function dateFromConfig(config) {
18759-    var i, date, input = [], currentDate,
18760-      yearToUse, fixYear, w, temp, lang, weekday, week;
18761-
18762-    if (config._d) {
18763-      return;
18764-    }
18765-
18766-    currentDate = currentDateArray(config);
18767-
18768-    //compute day of the year from weeks and weekdays
18769-    if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
18770-      fixYear = function (val) {
18771-        var int_val = parseInt(val, 10);
18772-        return val ?
18773-          (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) :
18774-          (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]);
18775-      };
18776-
18777-      w = config._w;
18778-      if (w.GG != null || w.W != null || w.E != null) {
18779-        temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1);
18780-      }
18781-      else {
18782-        lang = getLangDefinition(config._l);
18783-        weekday = w.d != null ?  parseWeekday(w.d, lang) :
18784-          (w.e != null ?  parseInt(w.e, 10) + lang._week.dow : 0);
18785-
18786-        week = parseInt(w.w, 10) || 1;
18787-
18788-        //if we're parsing 'd', then the low day numbers may be next week
18789-        if (w.d != null && weekday < lang._week.dow) {
18790-          week++;
18791-        }
18792-
18793-        temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow);
18794-      }
18795-
18796-      config._a[YEAR] = temp.year;
18797-      config._dayOfYear = temp.dayOfYear;
18798-    }
18799-
18800-    //if the day of the year is set, figure out what it is
18801-    if (config._dayOfYear) {
18802-      yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR];
18803-
18804-      if (config._dayOfYear > daysInYear(yearToUse)) {
18805-        config._pf._overflowDayOfYear = true;
18806-      }
18807-
18808-      date = makeUTCDate(yearToUse, 0, config._dayOfYear);
18809-      config._a[MONTH] = date.getUTCMonth();
18810-      config._a[DATE] = date.getUTCDate();
18811-    }
18812-
18813-    // Default to current date.
18814-    // * if no year, month, day of month are given, default to today
18815-    // * if day of month is given, default month and year
18816-    // * if month is given, default only year
18817-    // * if year is given, don't default anything
18818-    for (i = 0; i < 3 && config._a[i] == null; ++i) {
18819-      config._a[i] = input[i] = currentDate[i];
18820-    }
18821-
18822-    // Zero out whatever was not defaulted, including time
18823-    for (; i < 7; i++) {
18824-      config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
18825-    }
18826-
18827-    // add the offsets to the time to be parsed so that we can have a clean array for checking isValid
18828-    input[HOUR] += toInt((config._tzm || 0) / 60);
18829-    input[MINUTE] += toInt((config._tzm || 0) % 60);
18830-
18831-    config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
18832-  }
18833-
18834-  function dateFromObject(config) {
18835-    var normalizedInput;
18836-
18837-    if (config._d) {
18838-      return;
18839-    }
18840-
18841-    normalizedInput = normalizeObjectUnits(config._i);
18842-    config._a = [
18843-      normalizedInput.year,
18844-      normalizedInput.month,
18845-      normalizedInput.day,
18846-      normalizedInput.hour,
18847-      normalizedInput.minute,
18848-      normalizedInput.second,
18849-      normalizedInput.millisecond
18850-    ];
18851-
18852-    dateFromConfig(config);
18853-  }
18854-
18855-  function currentDateArray(config) {
18856-    var now = new Date();
18857-    if (config._useUTC) {
18858-      return [
18859-        now.getUTCFullYear(),
18860-        now.getUTCMonth(),
18861-        now.getUTCDate()
18862-      ];
18863-    } else {
18864-      return [now.getFullYear(), now.getMonth(), now.getDate()];
18865-    }
18866-  }
18867-
18868-  // date from string and format string
18869-  function makeDateFromStringAndFormat(config) {
18870-
18871-    config._a = [];
18872-    config._pf.empty = true;
18873-
18874-    // This array is used to make a Date, either with `new Date` or `Date.UTC`
18875-    var lang = getLangDefinition(config._l),
18876-      string = '' + config._i,
18877-      i, parsedInput, tokens, token, skipped,
18878-      stringLength = string.length,
18879-      totalParsedInputLength = 0;
18880-
18881-    tokens = expandFormat(config._f, lang).match(formattingTokens) || [];
18882-
18883-    for (i = 0; i < tokens.length; i++) {
18884-      token = tokens[i];
18885-      parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
18886-      if (parsedInput) {
18887-        skipped = string.substr(0, string.indexOf(parsedInput));
18888-        if (skipped.length > 0) {
18889-          config._pf.unusedInput.push(skipped);
18890-        }
18891-        string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
18892-        totalParsedInputLength += parsedInput.length;
18893-      }
18894-      // don't parse if it's not a known token
18895-      if (formatTokenFunctions[token]) {
18896-        if (parsedInput) {
18897-          config._pf.empty = false;
18898-        }
18899-        else {
18900-          config._pf.unusedTokens.push(token);
18901-        }
18902-        addTimeToArrayFromToken(token, parsedInput, config);
18903-      }
18904-      else if (config._strict && !parsedInput) {
18905-        config._pf.unusedTokens.push(token);
18906-      }
18907-    }
18908-
18909-    // add remaining unparsed input length to the string
18910-    config._pf.charsLeftOver = stringLength - totalParsedInputLength;
18911-    if (string.length > 0) {
18912-      config._pf.unusedInput.push(string);
18913-    }
18914-
18915-    // handle am pm
18916-    if (config._isPm && config._a[HOUR] < 12) {
18917-      config._a[HOUR] += 12;
18918-    }
18919-    // if is 12 am, change hours to 0
18920-    if (config._isPm === false && config._a[HOUR] === 12) {
18921-      config._a[HOUR] = 0;
18922-    }
18923-
18924-    dateFromConfig(config);
18925-    checkOverflow(config);
18926-  }
18927-
18928-  function unescapeFormat(s) {
18929-    return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
18930-      return p1 || p2 || p3 || p4;
18931-    });
18932-  }
18933-
18934-  // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
18935-  function regexpEscape(s) {
18936-    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
18937-  }
18938-
18939-  // date from string and array of format strings
18940-  function makeDateFromStringAndArray(config) {
18941-    var tempConfig,
18942-      bestMoment,
18943-
18944-      scoreToBeat,
18945-      i,
18946-      currentScore;
18947-
18948-    if (config._f.length === 0) {
18949-      config._pf.invalidFormat = true;
18950-      config._d = new Date(NaN);
18951-      return;
18952-    }
18953-
18954-    for (i = 0; i < config._f.length; i++) {
18955-      currentScore = 0;
18956-      tempConfig = extend({}, config);
18957-      initializeParsingFlags(tempConfig);
18958-      tempConfig._f = config._f[i];
18959-      makeDateFromStringAndFormat(tempConfig);
18960-
18961-      if (!isValid(tempConfig)) {
18962-        continue;
18963-      }
18964-
18965-      // if there is any input that was not parsed add a penalty for that format
18966-      currentScore += tempConfig._pf.charsLeftOver;
18967-
18968-      //or tokens
18969-      currentScore += tempConfig._pf.unusedTokens.length * 10;
18970-
18971-      tempConfig._pf.score = currentScore;
18972-
18973-      if (scoreToBeat == null || currentScore < scoreToBeat) {
18974-        scoreToBeat = currentScore;
18975-        bestMoment = tempConfig;
18976-      }
18977-    }
18978-
18979-    extend(config, bestMoment || tempConfig);
18980-  }
18981-
18982-  // date from iso format
18983-  function makeDateFromString(config) {
18984-    var i,
18985-      string = config._i,
18986-      match = isoRegex.exec(string);
18987-
18988-    if (match) {
18989-      config._pf.iso = true;
18990-      for (i = 4; i > 0; i--) {
18991-        if (match[i]) {
18992-          // match[5] should be "T" or undefined
18993-          config._f = isoDates[i - 1] + (match[6] || " ");
18994-          break;
18995-        }
18996-      }
18997-      for (i = 0; i < 4; i++) {
18998-        if (isoTimes[i][1].exec(string)) {
18999-          config._f += isoTimes[i][0];
19000-          break;
19001-        }
19002-      }
19003-      if (string.match(parseTokenTimezone)) {
19004-        config._f += "Z";
19005-      }
19006-      makeDateFromStringAndFormat(config);
19007-    }
19008-    else {
19009-      config._d = new Date(string);
19010-    }
19011-  }
19012-
19013-  function makeDateFromInput(config) {
19014-    var input = config._i,
19015-      matched = aspNetJsonRegex.exec(input);
19016-
19017-    if (input === undefined) {
19018-      config._d = new Date();
19019-    } else if (matched) {
19020-      config._d = new Date(+matched[1]);
19021-    } else if (typeof input === 'string') {
19022-      makeDateFromString(config);
19023-    } else if (isArray(input)) {
19024-      config._a = input.slice(0);
19025-      dateFromConfig(config);
19026-    } else if (isDate(input)) {
19027-      config._d = new Date(+input);
19028-    } else if (typeof(input) === 'object') {
19029-      dateFromObject(config);
19030-    } else {
19031-      config._d = new Date(input);
19032-    }
19033-  }
19034-
19035-  function makeDate(y, m, d, h, M, s, ms) {
19036-    //can't just apply() to create a date:
19037-    //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
19038-    var date = new Date(y, m, d, h, M, s, ms);
19039-
19040-    //the date constructor doesn't accept years < 1970
19041-    if (y < 1970) {
19042-      date.setFullYear(y);
19043-    }
19044-    return date;
19045-  }
19046-
19047-  function makeUTCDate(y) {
19048-    var date = new Date(Date.UTC.apply(null, arguments));
19049-    if (y < 1970) {
19050-      date.setUTCFullYear(y);
19051-    }
19052-    return date;
19053-  }
19054-
19055-  function parseWeekday(input, language) {
19056-    if (typeof input === 'string') {
19057-      if (!isNaN(input)) {
19058-        input = parseInt(input, 10);
19059-      }
19060-      else {
19061-        input = language.weekdaysParse(input);
19062-        if (typeof input !== 'number') {
19063-          return null;
19064-        }
19065-      }
19066-    }
19067-    return input;
19068-  }
19069-
19070-  /************************************
19071-   Relative Time
19072-   ************************************/
19073-
19074-
19075-  // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
19076-  function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
19077-    return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
19078-  }
19079-
19080-  function relativeTime(milliseconds, withoutSuffix, lang) {
19081-    var seconds = round(Math.abs(milliseconds) / 1000),
19082-      minutes = round(seconds / 60),
19083-      hours = round(minutes / 60),
19084-      days = round(hours / 24),
19085-      years = round(days / 365),
19086-      args = seconds < 45 && ['s', seconds] ||
19087-        minutes === 1 && ['m'] ||
19088-        minutes < 45 && ['mm', minutes] ||
19089-        hours === 1 && ['h'] ||
19090-        hours < 22 && ['hh', hours] ||
19091-        days === 1 && ['d'] ||
19092-        days <= 25 && ['dd', days] ||
19093-        days <= 45 && ['M'] ||
19094-        days < 345 && ['MM', round(days / 30)] ||
19095-        years === 1 && ['y'] || ['yy', years];
19096-    args[2] = withoutSuffix;
19097-    args[3] = milliseconds > 0;
19098-    args[4] = lang;
19099-    return substituteTimeAgo.apply({}, args);
19100-  }
19101-
19102-
19103-  /************************************
19104-   Week of Year
19105-   ************************************/
19106-
19107-
19108-  // firstDayOfWeek       0 = sun, 6 = sat
19109-  //                      the day of the week that starts the week
19110-  //                      (usually sunday or monday)
19111-  // firstDayOfWeekOfYear 0 = sun, 6 = sat
19112-  //                      the first week is the week that contains the first
19113-  //                      of this day of the week
19114-  //                      (eg. ISO weeks use thursday (4))
19115-  function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
19116-    var end = firstDayOfWeekOfYear - firstDayOfWeek,
19117-      daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
19118-      adjustedMoment;
19119-
19120-
19121-    if (daysToDayOfWeek > end) {
19122-      daysToDayOfWeek -= 7;
19123-    }
19124-
19125-    if (daysToDayOfWeek < end - 7) {
19126-      daysToDayOfWeek += 7;
19127-    }
19128-
19129-    adjustedMoment = moment(mom).add('d', daysToDayOfWeek);
19130-    return {
19131-      week: Math.ceil(adjustedMoment.dayOfYear() / 7),
19132-      year: adjustedMoment.year()
19133-    };
19134-  }
19135-
19136-  //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
19137-  function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
19138-    // The only solid way to create an iso date from year is to use
19139-    // a string format (Date.UTC handles only years > 1900). Don't ask why
19140-    // it doesn't need Z at the end.
19141-    var d = new Date(leftZeroFill(year, 6, true) + '-01-01').getUTCDay(),
19142-      daysToAdd, dayOfYear;
19143-
19144-    weekday = weekday != null ? weekday : firstDayOfWeek;
19145-    daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0);
19146-    dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
19147-
19148-    return {
19149-      year: dayOfYear > 0 ? year : year - 1,
19150-      dayOfYear: dayOfYear > 0 ?  dayOfYear : daysInYear(year - 1) + dayOfYear
19151-    };
19152-  }
19153-
19154-  /************************************
19155-   Top Level Functions
19156-   ************************************/
19157-
19158-  function makeMoment(config) {
19159-    var input = config._i,
19160-      format = config._f;
19161-
19162-    if (typeof config._pf === 'undefined') {
19163-      initializeParsingFlags(config);
19164-    }
19165-
19166-    if (input === null) {
19167-      return moment.invalid({nullInput: true});
19168-    }
19169-
19170-    if (typeof input === 'string') {
19171-      config._i = input = getLangDefinition().preparse(input);
19172-    }
19173-
19174-    if (moment.isMoment(input)) {
19175-      config = extend({}, input);
19176-
19177-      config._d = new Date(+input._d);
19178-    } else if (format) {
19179-      if (isArray(format)) {
19180-        makeDateFromStringAndArray(config);
19181-      } else {
19182-        makeDateFromStringAndFormat(config);
19183-      }
19184-    } else {
19185-      makeDateFromInput(config);
19186-    }
19187-
19188-    return new Moment(config);
19189-  }
19190-
19191-  moment = function (input, format, lang, strict) {
19192-    if (typeof(lang) === "boolean") {
19193-      strict = lang;
19194-      lang = undefined;
19195-    }
19196-    return makeMoment({
19197-      _i : input,
19198-      _f : format,
19199-      _l : lang,
19200-      _strict : strict,
19201-      _isUTC : false
19202-    });
19203-  };
19204-
19205-  // creating with utc
19206-  moment.utc = function (input, format, lang, strict) {
19207-    var m;
19208-
19209-    if (typeof(lang) === "boolean") {
19210-      strict = lang;
19211-      lang = undefined;
19212-    }
19213-    m = makeMoment({
19214-      _useUTC : true,
19215-      _isUTC : true,
19216-      _l : lang,
19217-      _i : input,
19218-      _f : format,
19219-      _strict : strict
19220-    }).utc();
19221-
19222-    return m;
19223-  };
19224-
19225-  // creating with unix timestamp (in seconds)
19226-  moment.unix = function (input) {
19227-    return moment(input * 1000);
19228-  };
19229-
19230-  // duration
19231-  moment.duration = function (input, key) {
19232-    var duration = input,
19233-      // matching against regexp is expensive, do it on demand
19234-      match = null,
19235-      sign,
19236-      ret,
19237-      parseIso;
19238-
19239-    if (moment.isDuration(input)) {
19240-      duration = {
19241-        ms: input._milliseconds,
19242-        d: input._days,
19243-        M: input._months
19244-      };
19245-    } else if (typeof input === 'number') {
19246-      duration = {};
19247-      if (key) {
19248-        duration[key] = input;
19249-      } else {
19250-        duration.milliseconds = input;
19251-      }
19252-    } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {
19253-      sign = (match[1] === "-") ? -1 : 1;
19254-      duration = {
19255-        y: 0,
19256-        d: toInt(match[DATE]) * sign,
19257-        h: toInt(match[HOUR]) * sign,
19258-        m: toInt(match[MINUTE]) * sign,
19259-        s: toInt(match[SECOND]) * sign,
19260-        ms: toInt(match[MILLISECOND]) * sign
19261-      };
19262-    } else if (!!(match = isoDurationRegex.exec(input))) {
19263-      sign = (match[1] === "-") ? -1 : 1;
19264-      parseIso = function (inp) {
19265-        // We'd normally use ~~inp for this, but unfortunately it also
19266-        // converts floats to ints.
19267-        // inp may be undefined, so careful calling replace on it.
19268-        var res = inp && parseFloat(inp.replace(',', '.'));
19269-        // apply sign while we're at it
19270-        return (isNaN(res) ? 0 : res) * sign;
19271-      };
19272-      duration = {
19273-        y: parseIso(match[2]),
19274-        M: parseIso(match[3]),
19275-        d: parseIso(match[4]),
19276-        h: parseIso(match[5]),
19277-        m: parseIso(match[6]),
19278-        s: parseIso(match[7]),
19279-        w: parseIso(match[8])
19280-      };
19281-    }
19282-
19283-    ret = new Duration(duration);
19284-
19285-    if (moment.isDuration(input) && input.hasOwnProperty('_lang')) {
19286-      ret._lang = input._lang;
19287-    }
19288-
19289-    return ret;
19290-  };
19291-
19292-  // version number
19293-  moment.version = VERSION;
19294-
19295-  // default format
19296-  moment.defaultFormat = isoFormat;
19297-
19298-  // This function will be called whenever a moment is mutated.
19299-  // It is intended to keep the offset in sync with the timezone.
19300-  moment.updateOffset = function () {};
19301-
19302-  // This function will load languages and then set the global language.  If
19303-  // no arguments are passed in, it will simply return the current global
19304-  // language key.
19305-  moment.lang = function (key, values) {
19306-    var r;
19307-    if (!key) {
19308-      return moment.fn._lang._abbr;
19309-    }
19310-    if (values) {
19311-      loadLang(normalizeLanguage(key), values);
19312-    } else if (values === null) {
19313-      unloadLang(key);
19314-      key = 'en';
19315-    } else if (!languages[key]) {
19316-      getLangDefinition(key);
19317-    }
19318-    r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
19319-    return r._abbr;
19320-  };
19321-
19322-  // returns language data
19323-  moment.langData = function (key) {
19324-    if (key && key._lang && key._lang._abbr) {
19325-      key = key._lang._abbr;
19326-    }
19327-    return getLangDefinition(key);
19328-  };
19329-
19330-  // compare moment object
19331-  moment.isMoment = function (obj) {
19332-    return obj instanceof Moment;
19333-  };
19334-
19335-  // for typechecking Duration objects
19336-  moment.isDuration = function (obj) {
19337-    return obj instanceof Duration;
19338-  };
19339-
19340-  for (i = lists.length - 1; i >= 0; --i) {
19341-    makeList(lists[i]);
19342-  }
19343-
19344-  moment.normalizeUnits = function (units) {
19345-    return normalizeUnits(units);
19346-  };
19347-
19348-  moment.invalid = function (flags) {
19349-    var m = moment.utc(NaN);
19350-    if (flags != null) {
19351-      extend(m._pf, flags);
19352-    }
19353-    else {
19354-      m._pf.userInvalidated = true;
19355-    }
19356-
19357-    return m;
19358-  };
19359-
19360-  moment.parseZone = function (input) {
19361-    return moment(input).parseZone();
19362-  };
19363-
19364-  /************************************
19365-   Moment Prototype
19366-   ************************************/
19367-
19368-
19369-  extend(moment.fn = Moment.prototype, {
19370-
19371-    clone : function () {
19372-      return moment(this);
19373-    },
19374-
19375-    valueOf : function () {
19376-      return +this._d + ((this._offset || 0) * 60000);
19377-    },
19378-
19379-    unix : function () {
19380-      return Math.floor(+this / 1000);
19381-    },
19382-
19383-    toString : function () {
19384-      return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
19385-    },
19386-
19387-    toDate : function () {
19388-      return this._offset ? new Date(+this) : this._d;
19389-    },
19390-
19391-    toISOString : function () {
19392-      var m = moment(this).utc();
19393-      if (0 < m.year() && m.year() <= 9999) {
19394-        return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
19395-      } else {
19396-        return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
19397-      }
19398-    },
19399-
19400-    toArray : function () {
19401-      var m = this;
19402-      return [
19403-        m.year(),
19404-        m.month(),
19405-        m.date(),
19406-        m.hours(),
19407-        m.minutes(),
19408-        m.seconds(),
19409-        m.milliseconds()
19410-      ];
19411-    },
19412-
19413-    isValid : function () {
19414-      return isValid(this);
19415-    },
19416-
19417-    isDSTShifted : function () {
19418-
19419-      if (this._a) {
19420-        return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
19421-      }
19422-
19423-      return false;
19424-    },
19425-
19426-    parsingFlags : function () {
19427-      return extend({}, this._pf);
19428-    },
19429-
19430-    invalidAt: function () {
19431-      return this._pf.overflow;
19432-    },
19433-
19434-    utc : function () {
19435-      return this.zone(0);
19436-    },
19437-
19438-    local : function () {
19439-      this.zone(0);
19440-      this._isUTC = false;
19441-      return this;
19442-    },
19443-
19444-    format : function (inputString) {
19445-      var output = formatMoment(this, inputString || moment.defaultFormat);
19446-      return this.lang().postformat(output);
19447-    },
19448-
19449-    add : function (input, val) {
19450-      var dur;
19451-      // switch args to support add('s', 1) and add(1, 's')
19452-      if (typeof input === 'string') {
19453-        dur = moment.duration(+val, input);
19454-      } else {
19455-        dur = moment.duration(input, val);
19456-      }
19457-      addOrSubtractDurationFromMoment(this, dur, 1);
19458-      return this;
19459-    },
19460-
19461-    subtract : function (input, val) {
19462-      var dur;
19463-      // switch args to support subtract('s', 1) and subtract(1, 's')
19464-      if (typeof input === 'string') {
19465-        dur = moment.duration(+val, input);
19466-      } else {
19467-        dur = moment.duration(input, val);
19468-      }
19469-      addOrSubtractDurationFromMoment(this, dur, -1);
19470-      return this;
19471-    },
19472-
19473-    diff : function (input, units, asFloat) {
19474-      var that = makeAs(input, this),
19475-        zoneDiff = (this.zone() - that.zone()) * 6e4,
19476-        diff, output;
19477-
19478-      units = normalizeUnits(units);
19479-
19480-      if (units === 'year' || units === 'month') {
19481-        // average number of days in the months in the given dates
19482-        diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
19483-        // difference in months
19484-        output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
19485-        // adjust by taking difference in days, average number of days
19486-        // and dst in the given months.
19487-        output += ((this - moment(this).startOf('month')) -
19488-          (that - moment(that).startOf('month'))) / diff;
19489-        // same as above but with zones, to negate all dst
19490-        output -= ((this.zone() - moment(this).startOf('month').zone()) -
19491-          (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff;
19492-        if (units === 'year') {
19493-          output = output / 12;
19494-        }
19495-      } else {
19496-        diff = (this - that);
19497-        output = units === 'second' ? diff / 1e3 : // 1000
19498-          units === 'minute' ? diff / 6e4 : // 1000 * 60
19499-            units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
19500-              units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
19501-                units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
19502-                  diff;
19503-      }
19504-      return asFloat ? output : absRound(output);
19505-    },
19506-
19507-    from : function (time, withoutSuffix) {
19508-      return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
19509-    },
19510-
19511-    fromNow : function (withoutSuffix) {
19512-      return this.from(moment(), withoutSuffix);
19513-    },
19514-
19515-    calendar : function () {
19516-      // We want to compare the start of today, vs this.
19517-      // Getting start-of-today depends on whether we're zone'd or not.
19518-      var sod = makeAs(moment(), this).startOf('day'),
19519-        diff = this.diff(sod, 'days', true),
19520-        format = diff < -6 ? 'sameElse' :
19521-          diff < -1 ? 'lastWeek' :
19522-            diff < 0 ? 'lastDay' :
19523-              diff < 1 ? 'sameDay' :
19524-                diff < 2 ? 'nextDay' :
19525-                  diff < 7 ? 'nextWeek' : 'sameElse';
19526-      return this.format(this.lang().calendar(format, this));
19527-    },
19528-
19529-    isLeapYear : function () {
19530-      return isLeapYear(this.year());
19531-    },
19532-
19533-    isDST : function () {
19534-      return (this.zone() < this.clone().month(0).zone() ||
19535-      this.zone() < this.clone().month(5).zone());
19536-    },
19537-
19538-    day : function (input) {
19539-      var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
19540-      if (input != null) {
19541-        input = parseWeekday(input, this.lang());
19542-        return this.add({ d : input - day });
19543-      } else {
19544-        return day;
19545-      }
19546-    },
19547-
19548-    month : function (input) {
19549-      var utc = this._isUTC ? 'UTC' : '',
19550-        dayOfMonth;
19551-
19552-      if (input != null) {
19553-        if (typeof input === 'string') {
19554-          input = this.lang().monthsParse(input);
19555-          if (typeof input !== 'number') {
19556-            return this;
19557-          }
19558-        }
19559-
19560-        dayOfMonth = this.date();
19561-        this.date(1);
19562-        this._d['set' + utc + 'Month'](input);
19563-        this.date(Math.min(dayOfMonth, this.daysInMonth()));
19564-
19565-        moment.updateOffset(this);
19566-        return this;
19567-      } else {
19568-        return this._d['get' + utc + 'Month']();
19569-      }
19570-    },
19571-
19572-    startOf: function (units) {
19573-      units = normalizeUnits(units);
19574-      // the following switch intentionally omits break keywords
19575-      // to utilize falling through the cases.
19576-      switch (units) {
19577-        case 'year':
19578-          this.month(0);
19579-        /* falls through */
19580-        case 'month':
19581-          this.date(1);
19582-        /* falls through */
19583-        case 'week':
19584-        case 'isoWeek':
19585-        case 'day':
19586-          this.hours(0);
19587-        /* falls through */
19588-        case 'hour':
19589-          this.minutes(0);
19590-        /* falls through */
19591-        case 'minute':
19592-          this.seconds(0);
19593-        /* falls through */
19594-        case 'second':
19595-          this.milliseconds(0);
19596-        /* falls through */
19597-      }
19598-
19599-      // weeks are a special case
19600-      if (units === 'week') {
19601-        this.weekday(0);
19602-      } else if (units === 'isoWeek') {
19603-        this.isoWeekday(1);
19604-      }
19605-
19606-      return this;
19607-    },
19608-
19609-    endOf: function (units) {
19610-      units = normalizeUnits(units);
19611-      return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1);
19612-    },
19613-
19614-    isAfter: function (input, units) {
19615-      units = typeof units !== 'undefined' ? units : 'millisecond';
19616-      return +this.clone().startOf(units) > +moment(input).startOf(units);
19617-    },
19618-
19619-    isBefore: function (input, units) {
19620-      units = typeof units !== 'undefined' ? units : 'millisecond';
19621-      return +this.clone().startOf(units) < +moment(input).startOf(units);
19622-    },
19623-
19624-    isSame: function (input, units) {
19625-      units = units || 'ms';
19626-      return +this.clone().startOf(units) === +makeAs(input, this).startOf(units);
19627-    },
19628-
19629-    min: function (other) {
19630-      other = moment.apply(null, arguments);
19631-      return other < this ? this : other;
19632-    },
19633-
19634-    max: function (other) {
19635-      other = moment.apply(null, arguments);
19636-      return other > this ? this : other;
19637-    },
19638-
19639-    zone : function (input) {
19640-      var offset = this._offset || 0;
19641-      if (input != null) {
19642-        if (typeof input === "string") {
19643-          input = timezoneMinutesFromString(input);
19644-        }
19645-        if (Math.abs(input) < 16) {
19646-          input = input * 60;
19647-        }
19648-        this._offset = input;
19649-        this._isUTC = true;
19650-        if (offset !== input) {
19651-          addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true);
19652-        }
19653-      } else {
19654-        return this._isUTC ? offset : this._d.getTimezoneOffset();
19655-      }
19656-      return this;
19657-    },
19658-
19659-    zoneAbbr : function () {
19660-      return this._isUTC ? "UTC" : "";
19661-    },
19662-
19663-    zoneName : function () {
19664-      return this._isUTC ? "Coordinated Universal Time" : "";
19665-    },
19666-
19667-    parseZone : function () {
19668-      if (this._tzm) {
19669-        this.zone(this._tzm);
19670-      } else if (typeof this._i === 'string') {
19671-        this.zone(this._i);
19672-      }
19673-      return this;
19674-    },
19675-
19676-    hasAlignedHourOffset : function (input) {
19677-      if (!input) {
19678-        input = 0;
19679-      }
19680-      else {
19681-        input = moment(input).zone();
19682-      }
19683-
19684-      return (this.zone() - input) % 60 === 0;
19685-    },
19686-
19687-    daysInMonth : function () {
19688-      return daysInMonth(this.year(), this.month());
19689-    },
19690-
19691-    dayOfYear : function (input) {
19692-      var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
19693-      return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
19694-    },
19695-
19696-    quarter : function () {
19697-      return Math.ceil((this.month() + 1.0) / 3.0);
19698-    },
19699-
19700-    weekYear : function (input) {
19701-      var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year;
19702-      return input == null ? year : this.add("y", (input - year));
19703-    },
19704-
19705-    isoWeekYear : function (input) {
19706-      var year = weekOfYear(this, 1, 4).year;
19707-      return input == null ? year : this.add("y", (input - year));
19708-    },
19709-
19710-    week : function (input) {
19711-      var week = this.lang().week(this);
19712-      return input == null ? week : this.add("d", (input - week) * 7);
19713-    },
19714-
19715-    isoWeek : function (input) {
19716-      var week = weekOfYear(this, 1, 4).week;
19717-      return input == null ? week : this.add("d", (input - week) * 7);
19718-    },
19719-
19720-    weekday : function (input) {
19721-      var weekday = (this.day() + 7 - this.lang()._week.dow) % 7;
19722-      return input == null ? weekday : this.add("d", input - weekday);
19723-    },
19724-
19725-    isoWeekday : function (input) {
19726-      // behaves the same as moment#day except
19727-      // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
19728-      // as a setter, sunday should belong to the previous week.
19729-      return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
19730-    },
19731-
19732-    get : function (units) {
19733-      units = normalizeUnits(units);
19734-      return this[units]();
19735-    },
19736-
19737-    set : function (units, value) {
19738-      units = normalizeUnits(units);
19739-      if (typeof this[units] === 'function') {
19740-        this[units](value);
19741-      }
19742-      return this;
19743-    },
19744-
19745-    // If passed a language key, it will set the language for this
19746-    // instance.  Otherwise, it will return the language configuration
19747-    // variables for this instance.
19748-    lang : function (key) {
19749-      if (key === undefined) {
19750-        return this._lang;
19751-      } else {
19752-        this._lang = getLangDefinition(key);
19753-        return this;
19754-      }
19755-    }
19756-  });
19757-
19758-  // helper for adding shortcuts
19759-  function makeGetterAndSetter(name, key) {
19760-    moment.fn[name] = moment.fn[name + 's'] = function (input) {
19761-      var utc = this._isUTC ? 'UTC' : '';
19762-      if (input != null) {
19763-        this._d['set' + utc + key](input);
19764-        moment.updateOffset(this);
19765-        return this;
19766-      } else {
19767-        return this._d['get' + utc + key]();
19768-      }
19769-    };
19770-  }
19771-
19772-  // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
19773-  for (i = 0; i < proxyGettersAndSetters.length; i ++) {
19774-    makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]);
19775-  }
19776-
19777-  // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
19778-  makeGetterAndSetter('year', 'FullYear');
19779-
19780-  // add plural methods
19781-  moment.fn.days = moment.fn.day;
19782-  moment.fn.months = moment.fn.month;
19783-  moment.fn.weeks = moment.fn.week;
19784-  moment.fn.isoWeeks = moment.fn.isoWeek;
19785-
19786-  // add aliased format methods
19787-  moment.fn.toJSON = moment.fn.toISOString;
19788-
19789-  /************************************
19790-   Duration Prototype
19791-   ************************************/
19792-
19793-
19794-  extend(moment.duration.fn = Duration.prototype, {
19795-
19796-    _bubble : function () {
19797-      var milliseconds = this._milliseconds,
19798-        days = this._days,
19799-        months = this._months,
19800-        data = this._data,
19801-        seconds, minutes, hours, years;
19802-
19803-      // The following code bubbles up values, see the tests for
19804-      // examples of what that means.
19805-      data.milliseconds = milliseconds % 1000;
19806-
19807-      seconds = absRound(milliseconds / 1000);
19808-      data.seconds = seconds % 60;
19809-
19810-      minutes = absRound(seconds / 60);
19811-      data.minutes = minutes % 60;
19812-
19813-      hours = absRound(minutes / 60);
19814-      data.hours = hours % 24;
19815-
19816-      days += absRound(hours / 24);
19817-      data.days = days % 30;
19818-
19819-      months += absRound(days / 30);
19820-      data.months = months % 12;
19821-
19822-      years = absRound(months / 12);
19823-      data.years = years;
19824-    },
19825-
19826-    weeks : function () {
19827-      return absRound(this.days() / 7);
19828-    },
19829-
19830-    valueOf : function () {
19831-      return this._milliseconds +
19832-        this._days * 864e5 +
19833-        (this._months % 12) * 2592e6 +
19834-        toInt(this._months / 12) * 31536e6;
19835-    },
19836-
19837-    humanize : function (withSuffix) {
19838-      var difference = +this,
19839-        output = relativeTime(difference, !withSuffix, this.lang());
19840-
19841-      if (withSuffix) {
19842-        output = this.lang().pastFuture(difference, output);
19843-      }
19844-
19845-      return this.lang().postformat(output);
19846-    },
19847-
19848-    add : function (input, val) {
19849-      // supports only 2.0-style add(1, 's') or add(moment)
19850-      var dur = moment.duration(input, val);
19851-
19852-      this._milliseconds += dur._milliseconds;
19853-      this._days += dur._days;
19854-      this._months += dur._months;
19855-
19856-      this._bubble();
19857-
19858-      return this;
19859-    },
19860-
19861-    subtract : function (input, val) {
19862-      var dur = moment.duration(input, val);
19863-
19864-      this._milliseconds -= dur._milliseconds;
19865-      this._days -= dur._days;
19866-      this._months -= dur._months;
19867-
19868-      this._bubble();
19869-
19870-      return this;
19871-    },
19872-
19873-    get : function (units) {
19874-      units = normalizeUnits(units);
19875-      return this[units.toLowerCase() + 's']();
19876-    },
19877-
19878-    as : function (units) {
19879-      units = normalizeUnits(units);
19880-      return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's']();
19881-    },
19882-
19883-    lang : moment.fn.lang,
19884-
19885-    toIsoString : function () {
19886-      // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
19887-      var years = Math.abs(this.years()),
19888-        months = Math.abs(this.months()),
19889-        days = Math.abs(this.days()),
19890-        hours = Math.abs(this.hours()),
19891-        minutes = Math.abs(this.minutes()),
19892-        seconds = Math.abs(this.seconds() + this.milliseconds() / 1000);
19893-
19894-      if (!this.asSeconds()) {
19895-        // this is the same as C#'s (Noda) and python (isodate)...
19896-        // but not other JS (goog.date)
19897-        return 'P0D';
19898-      }
19899-
19900-      return (this.asSeconds() < 0 ? '-' : '') +
19901-        'P' +
19902-        (years ? years + 'Y' : '') +
19903-        (months ? months + 'M' : '') +
19904-        (days ? days + 'D' : '') +
19905-        ((hours || minutes || seconds) ? 'T' : '') +
19906-        (hours ? hours + 'H' : '') +
19907-        (minutes ? minutes + 'M' : '') +
19908-        (seconds ? seconds + 'S' : '');
19909-    }
19910-  });
19911-
19912-  function makeDurationGetter(name) {
19913-    moment.duration.fn[name] = function () {
19914-      return this._data[name];
19915-    };
19916-  }
19917-
19918-  function makeDurationAsGetter(name, factor) {
19919-    moment.duration.fn['as' + name] = function () {
19920-      return +this / factor;
19921-    };
19922-  }
19923-
19924-  for (i in unitMillisecondFactors) {
19925-    if (unitMillisecondFactors.hasOwnProperty(i)) {
19926-      makeDurationAsGetter(i, unitMillisecondFactors[i]);
19927-      makeDurationGetter(i.toLowerCase());
19928-    }
19929-  }
19930-
19931-  makeDurationAsGetter('Weeks', 6048e5);
19932-  moment.duration.fn.asMonths = function () {
19933-    return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12;
19934-  };
19935-
19936-
19937-  /************************************
19938-   Default Lang
19939-   ************************************/
19940-
19941-
19942-  // Set default language, other languages will inherit from English.
19943-  moment.lang('en', {
19944-    ordinal : function (number) {
19945-      var b = number % 10,
19946-        output = (toInt(number % 100 / 10) === 1) ? 'th' :
19947-          (b === 1) ? 'st' :
19948-            (b === 2) ? 'nd' :
19949-              (b === 3) ? 'rd' : 'th';
19950-      return number + output;
19951-    }
19952-  });
19953-
19954-  /* EMBED_LANGUAGES */
19955-
19956-  /************************************
19957-   Exposing Moment
19958-   ************************************/
19959-
19960-  function makeGlobal(deprecate) {
19961-    var warned = false, local_moment = moment;
19962-    /*global ender:false */
19963-    if (typeof ender !== 'undefined') {
19964-      return;
19965-    }
19966-    // here, `this` means `window` in the browser, or `global` on the server
19967-    // add `moment` as a global object via a string identifier,
19968-    // for Closure Compiler "advanced" mode
19969-    if (deprecate) {
19970-      global.moment = function () {
19971-        if (!warned && console && console.warn) {
19972-          warned = true;
19973-          console.warn(
19974-            "Accessing Moment through the global scope is " +
19975-            "deprecated, and will be removed in an upcoming " +
19976-            "release.");
19977-        }
19978-        return local_moment.apply(null, arguments);
19979-      };
19980-      extend(global.moment, local_moment);
19981-    } else {
19982-      global['moment'] = moment;
19983-    }
19984-  }
19985-
19986-  // CommonJS module is defined
19987-  if (hasModule) {
19988-    module.exports = moment;
19989-    makeGlobal(true);
19990-  } else if (typeof define === "function" && define.amd) {
19991-    define("moment", function (require, exports, module) {
19992-      if (module.config && module.config() && module.config().noGlobal !== true) {
19993-        // If user provided noGlobal, he is aware of global
19994-        makeGlobal(module.config().noGlobal === undefined);
19995-      }
19996-
19997-      return moment;
19998-    });
19999-  } else {
20000-    makeGlobal();
20001-  }
20002-}).call(this);
20003diff --git a/lib/numeral/numeral.js b/lib/numeral/numeral.js
20004deleted file mode 100644
20005index e185b64..0000000
20006--- a/lib/numeral/numeral.js
20007+++ /dev/null
20008@@ -1,679 +0,0 @@
20009-/*!
20010- * numeral.js
20011- * version : 1.5.3
20012- * author : Adam Draper
20013- * license : MIT
20014- * http://adamwdraper.github.com/Numeral-js/
20015- */
20016-
20017-(function () {
20018-
20019-  /************************************
20020-   Constants
20021-   ************************************/
20022-
20023-  var numeral,
20024-    VERSION = '1.5.3',
20025-    // internal storage for language config files
20026-    languages = {},
20027-    currentLanguage = 'en',
20028-    zeroFormat = null,
20029-    defaultFormat = '0,0',
20030-    // check for nodeJS
20031-    hasModule = (typeof module !== 'undefined' && module.exports);
20032-
20033-
20034-  /************************************
20035-   Constructors
20036-   ************************************/
20037-
20038-
20039-  // Numeral prototype object
20040-  function Numeral (number) {
20041-    this._value = number;
20042-  }
20043-
20044-  /**
20045-   * Implementation of toFixed() that treats floats more like decimals
20046-   *
20047-   * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present
20048-   * problems for accounting- and finance-related software.
20049-   */
20050-  function toFixed (value, precision, roundingFunction, optionals) {
20051-    var power = Math.pow(10, precision),
20052-      optionalsRegExp,
20053-      output;
20054-
20055-    //roundingFunction = (roundingFunction !== undefined ? roundingFunction : Math.round);
20056-    // Multiply up by precision, round accurately, then divide and use native toFixed():
20057-    output = (roundingFunction(value * power) / power).toFixed(precision);
20058-
20059-    if (optionals) {
20060-      optionalsRegExp = new RegExp('0{1,' + optionals + '}$');
20061-      output = output.replace(optionalsRegExp, '');
20062-    }
20063-
20064-    return output;
20065-  }
20066-
20067-  /************************************
20068-   Formatting
20069-   ************************************/
20070-
20071-  // determine what type of formatting we need to do
20072-  function formatNumeral (n, format, roundingFunction) {
20073-    var output;
20074-
20075-    // figure out what kind of format we are dealing with
20076-    if (format.indexOf('$') > -1) { // currency!!!!!
20077-      output = formatCurrency(n, format, roundingFunction);
20078-    } else if (format.indexOf('%') > -1) { // percentage
20079-      output = formatPercentage(n, format, roundingFunction);
20080-    } else if (format.indexOf(':') > -1) { // time
20081-      output = formatTime(n, format);
20082-    } else { // plain ol' numbers or bytes
20083-      output = formatNumber(n._value, format, roundingFunction);
20084-    }
20085-
20086-    // return string
20087-    return output;
20088-  }
20089-
20090-  // revert to number
20091-  function unformatNumeral (n, string) {
20092-    var stringOriginal = string,
20093-      thousandRegExp,
20094-      millionRegExp,
20095-      billionRegExp,
20096-      trillionRegExp,
20097-      suffixes = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
20098-      bytesMultiplier = false,
20099-      power;
20100-
20101-    if (string.indexOf(':') > -1) {
20102-      n._value = unformatTime(string);
20103-    } else {
20104-      if (string === zeroFormat) {
20105-        n._value = 0;
20106-      } else {
20107-        if (languages[currentLanguage].delimiters.decimal !== '.') {
20108-          string = string.replace(/\./g,'').replace(languages[currentLanguage].delimiters.decimal, '.');
20109-        }
20110-
20111-        // see if abbreviations are there so that we can multiply to the correct number
20112-        thousandRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.thousand + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$');
20113-        millionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.million + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$');
20114-        billionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.billion + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$');
20115-        trillionRegExp = new RegExp('[^a-zA-Z]' + languages[currentLanguage].abbreviations.trillion + '(?:\\)|(\\' + languages[currentLanguage].currency.symbol + ')?(?:\\))?)?$');
20116-
20117-        // see if bytes are there so that we can multiply to the correct number
20118-        for (power = 0; power <= suffixes.length; power++) {
20119-          bytesMultiplier = (string.indexOf(suffixes[power]) > -1) ? Math.pow(1024, power + 1) : false;
20120-
20121-          if (bytesMultiplier) {
20122-            break;
20123-          }
20124-        }
20125-
20126-        // do some math to create our number
20127-        n._value = ((bytesMultiplier) ? bytesMultiplier : 1) * ((stringOriginal.match(thousandRegExp)) ? Math.pow(10, 3) : 1) * ((stringOriginal.match(millionRegExp)) ? Math.pow(10, 6) : 1) * ((stringOriginal.match(billionRegExp)) ? Math.pow(10, 9) : 1) * ((stringOriginal.match(trillionRegExp)) ? Math.pow(10, 12) : 1) * ((string.indexOf('%') > -1) ? 0.01 : 1) * (((string.split('-').length + Math.min(string.split('(').length-1, string.split(')').length-1)) % 2)? 1: -1) * Number(string.replace(/[^0-9\.]+/g, ''));
20128-
20129-        // round if we are talking about bytes
20130-        n._value = (bytesMultiplier) ? Math.ceil(n._value) : n._value;
20131-      }
20132-    }
20133-    return n._value;
20134-  }
20135-
20136-  function formatCurrency (n, format, roundingFunction) {
20137-    var symbolIndex = format.indexOf('$'),
20138-      openParenIndex = format.indexOf('('),
20139-      minusSignIndex = format.indexOf('-'),
20140-      space = '',
20141-      spliceIndex,
20142-      output;
20143-
20144-    // check for space before or after currency
20145-    if (format.indexOf(' $') > -1) {
20146-      space = ' ';
20147-      format = format.replace(' $', '');
20148-    } else if (format.indexOf('$ ') > -1) {
20149-      space = ' ';
20150-      format = format.replace('$ ', '');
20151-    } else {
20152-      format = format.replace('$', '');
20153-    }
20154-
20155-    // format the number
20156-    output = formatNumber(n._value, format, roundingFunction);
20157-
20158-    // position the symbol
20159-    if (symbolIndex <= 1) {
20160-      if (output.indexOf('(') > -1 || output.indexOf('-') > -1) {
20161-        output = output.split('');
20162-        spliceIndex = 1;
20163-        if (symbolIndex < openParenIndex || symbolIndex < minusSignIndex){
20164-          // the symbol appears before the "(" or "-"
20165-          spliceIndex = 0;
20166-        }
20167-        output.splice(spliceIndex, 0, languages[currentLanguage].currency.symbol + space);
20168-        output = output.join('');
20169-      } else {
20170-        output = languages[currentLanguage].currency.symbol + space + output;
20171-      }
20172-    } else {
20173-      if (output.indexOf(')') > -1) {
20174-        output = output.split('');
20175-        output.splice(-1, 0, space + languages[currentLanguage].currency.symbol);
20176-        output = output.join('');
20177-      } else {
20178-        output = output + space + languages[currentLanguage].currency.symbol;
20179-      }
20180-    }
20181-
20182-    return output;
20183-  }
20184-
20185-  function formatPercentage (n, format, roundingFunction) {
20186-    var space = '',
20187-      output,
20188-      value = n._value * 100;
20189-
20190-    // check for space before %
20191-    if (format.indexOf(' %') > -1) {
20192-      space = ' ';
20193-      format = format.replace(' %', '');
20194-    } else {
20195-      format = format.replace('%', '');
20196-    }
20197-
20198-    output = formatNumber(value, format, roundingFunction);
20199-
20200-    if (output.indexOf(')') > -1 ) {
20201-      output = output.split('');
20202-      output.splice(-1, 0, space + '%');
20203-      output = output.join('');
20204-    } else {
20205-      output = output + space + '%';
20206-    }
20207-
20208-    return output;
20209-  }
20210-
20211-  function formatTime (n) {
20212-    var hours = Math.floor(n._value/60/60),
20213-      minutes = Math.floor((n._value - (hours * 60 * 60))/60),
20214-      seconds = Math.round(n._value - (hours * 60 * 60) - (minutes * 60));
20215-    return hours + ':' + ((minutes < 10) ? '0' + minutes : minutes) + ':' + ((seconds < 10) ? '0' + seconds : seconds);
20216-  }
20217-
20218-  function unformatTime (string) {
20219-    var timeArray = string.split(':'),
20220-      seconds = 0;
20221-    // turn hours and minutes into seconds and add them all up
20222-    if (timeArray.length === 3) {
20223-      // hours
20224-      seconds = seconds + (Number(timeArray[0]) * 60 * 60);
20225-      // minutes
20226-      seconds = seconds + (Number(timeArray[1]) * 60);
20227-      // seconds
20228-      seconds = seconds + Number(timeArray[2]);
20229-    } else if (timeArray.length === 2) {
20230-      // minutes
20231-      seconds = seconds + (Number(timeArray[0]) * 60);
20232-      // seconds
20233-      seconds = seconds + Number(timeArray[1]);
20234-    }
20235-    return Number(seconds);
20236-  }
20237-
20238-  function formatNumber (value, format, roundingFunction) {
20239-    var negP = false,
20240-      signed = false,
20241-      optDec = false,
20242-      abbr = '',
20243-      abbrK = false, // force abbreviation to thousands
20244-      abbrM = false, // force abbreviation to millions
20245-      abbrB = false, // force abbreviation to billions
20246-      abbrT = false, // force abbreviation to trillions
20247-      abbrForce = false, // force abbreviation
20248-      bytes = '',
20249-      ord = '',
20250-      abs = Math.abs(value),
20251-      suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
20252-      min,
20253-      max,
20254-      power,
20255-      w,
20256-      precision,
20257-      thousands,
20258-      d = '',
20259-      neg = false;
20260-
20261-    // check if number is zero and a custom zero format has been set
20262-    if (value === 0 && zeroFormat !== null) {
20263-      return zeroFormat;
20264-    } else {
20265-      // see if we should use parentheses for negative number or if we should prefix with a sign
20266-      // if both are present we default to parentheses
20267-      if (format.indexOf('(') > -1) {
20268-        negP = true;
20269-        format = format.slice(1, -1);
20270-      } else if (format.indexOf('+') > -1) {
20271-        signed = true;
20272-        format = format.replace(/\+/g, '');
20273-      }
20274-
20275-      // see if abbreviation is wanted
20276-      if (format.indexOf('a') > -1) {
20277-        // check if abbreviation is specified
20278-        abbrK = format.indexOf('aK') >= 0;
20279-        abbrM = format.indexOf('aM') >= 0;
20280-        abbrB = format.indexOf('aB') >= 0;
20281-        abbrT = format.indexOf('aT') >= 0;
20282-        abbrForce = abbrK || abbrM || abbrB || abbrT;
20283-
20284-        // check for space before abbreviation
20285-        if (format.indexOf(' a') > -1) {
20286-          abbr = ' ';
20287-          format = format.replace(' a', '');
20288-        } else {
20289-          format = format.replace('a', '');
20290-        }
20291-
20292-        if (abs >= Math.pow(10, 12) && !abbrForce || abbrT) {
20293-          // trillion
20294-          abbr = abbr + languages[currentLanguage].abbreviations.trillion;
20295-          value = value / Math.pow(10, 12);
20296-        } else if (abs < Math.pow(10, 12) && abs >= Math.pow(10, 9) && !abbrForce || abbrB) {
20297-          // billion
20298-          abbr = abbr + languages[currentLanguage].abbreviations.billion;
20299-          value = value / Math.pow(10, 9);
20300-        } else if (abs < Math.pow(10, 9) && abs >= Math.pow(10, 6) && !abbrForce || abbrM) {
20301-          // million
20302-          abbr = abbr + languages[currentLanguage].abbreviations.million;
20303-          value = value / Math.pow(10, 6);
20304-        } else if (abs < Math.pow(10, 6) && abs >= Math.pow(10, 3) && !abbrForce || abbrK) {
20305-          // thousand
20306-          abbr = abbr + languages[currentLanguage].abbreviations.thousand;
20307-          value = value / Math.pow(10, 3);
20308-        }
20309-      }
20310-
20311-      // see if we are formatting bytes
20312-      if (format.indexOf('b') > -1) {
20313-        // check for space before
20314-        if (format.indexOf(' b') > -1) {
20315-          bytes = ' ';
20316-          format = format.replace(' b', '');
20317-        } else {
20318-          format = format.replace('b', '');
20319-        }
20320-
20321-        for (power = 0; power <= suffixes.length; power++) {
20322-          min = Math.pow(1024, power);
20323-          max = Math.pow(1024, power+1);
20324-
20325-          if (value >= min && value < max) {
20326-            bytes = bytes + suffixes[power];
20327-            if (min > 0) {
20328-              value = value / min;
20329-            }
20330-            break;
20331-          }
20332-        }
20333-      }
20334-
20335-      // see if ordinal is wanted
20336-      if (format.indexOf('o') > -1) {
20337-        // check for space before
20338-        if (format.indexOf(' o') > -1) {
20339-          ord = ' ';
20340-          format = format.replace(' o', '');
20341-        } else {
20342-          format = format.replace('o', '');
20343-        }
20344-
20345-        ord = ord + languages[currentLanguage].ordinal(value);
20346-      }
20347-
20348-      if (format.indexOf('[.]') > -1) {
20349-        optDec = true;
20350-        format = format.replace('[.]', '.');
20351-      }
20352-
20353-      w = value.toString().split('.')[0];
20354-      precision = format.split('.')[1];
20355-      thousands = format.indexOf(',');
20356-
20357-      if (precision) {
20358-        if (precision.indexOf('[') > -1) {
20359-          precision = precision.replace(']', '');
20360-          precision = precision.split('[');
20361-          d = toFixed(value, (precision[0].length + precision[1].length), roundingFunction, precision[1].length);
20362-        } else {
20363-          d = toFixed(value, precision.length, roundingFunction);
20364-        }
20365-
20366-        w = d.split('.')[0];
20367-
20368-        if (d.split('.')[1].length) {
20369-          d = languages[currentLanguage].delimiters.decimal + d.split('.')[1];
20370-        } else {
20371-          d = '';
20372-        }
20373-
20374-        if (optDec && Number(d.slice(1)) === 0) {
20375-          d = '';
20376-        }
20377-      } else {
20378-        w = toFixed(value, null, roundingFunction);
20379-      }
20380-
20381-      // format number
20382-      if (w.indexOf('-') > -1) {
20383-        w = w.slice(1);
20384-        neg = true;
20385-      }
20386-
20387-      if (thousands > -1) {
20388-        w = w.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + languages[currentLanguage].delimiters.thousands);
20389-      }
20390-
20391-      if (format.indexOf('.') === 0) {
20392-        w = '';
20393-      }
20394-
20395-      return ((negP && neg) ? '(' : '') + ((!negP && neg) ? '-' : '') + ((!neg && signed) ? '+' : '') + w + d + ((ord) ? ord : '') + ((abbr) ? abbr : '') + ((bytes) ? bytes : '') + ((negP && neg) ? ')' : '');
20396-    }
20397-  }
20398-
20399-  /************************************
20400-   Top Level Functions
20401-   ************************************/
20402-
20403-  numeral = function (input) {
20404-    if (numeral.isNumeral(input)) {
20405-      input = input.value();
20406-    } else if (input === 0 || typeof input === 'undefined') {
20407-      input = 0;
20408-    } else if (!Number(input)) {
20409-      input = numeral.fn.unformat(input);
20410-    }
20411-
20412-    return new Numeral(Number(input));
20413-  };
20414-
20415-  // version number
20416-  numeral.version = VERSION;
20417-
20418-  // compare numeral object
20419-  numeral.isNumeral = function (obj) {
20420-    return obj instanceof Numeral;
20421-  };
20422-
20423-  // This function will load languages and then set the global language.  If
20424-  // no arguments are passed in, it will simply return the current global
20425-  // language key.
20426-  numeral.language = function (key, values) {
20427-    if (!key) {
20428-      return currentLanguage;
20429-    }
20430-
20431-    if (key && !values) {
20432-      if(!languages[key]) {
20433-        throw new Error('Unknown language : ' + key);
20434-      }
20435-      currentLanguage = key;
20436-    }
20437-
20438-    if (values || !languages[key]) {
20439-      loadLanguage(key, values);
20440-    }
20441-
20442-    return numeral;
20443-  };
20444-
20445-  // This function provides access to the loaded language data.  If
20446-  // no arguments are passed in, it will simply return the current
20447-  // global language object.
20448-  numeral.languageData = function (key) {
20449-    if (!key) {
20450-      return languages[currentLanguage];
20451-    }
20452-
20453-    if (!languages[key]) {
20454-      throw new Error('Unknown language : ' + key);
20455-    }
20456-
20457-    return languages[key];
20458-  };
20459-
20460-  numeral.language('en', {
20461-    delimiters: {
20462-      thousands: ',',
20463-      decimal: '.'
20464-    },
20465-    abbreviations: {
20466-      thousand: 'k',
20467-      million: 'm',
20468-      billion: 'b',
20469-      trillion: 't'
20470-    },
20471-    ordinal: function (number) {
20472-      var b = number % 10;
20473-      return (~~ (number % 100 / 10) === 1) ? 'th' :
20474-        (b === 1) ? 'st' :
20475-          (b === 2) ? 'nd' :
20476-            (b === 3) ? 'rd' : 'th';
20477-    },
20478-    currency: {
20479-      symbol: '$'
20480-    }
20481-  });
20482-
20483-  numeral.zeroFormat = function (format) {
20484-    zeroFormat = typeof(format) === 'string' ? format : null;
20485-  };
20486-
20487-  numeral.defaultFormat = function (format) {
20488-    defaultFormat = typeof(format) === 'string' ? format : '0.0';
20489-  };
20490-
20491-  /************************************
20492-   Helpers
20493-   ************************************/
20494-
20495-  function loadLanguage(key, values) {
20496-    languages[key] = values;
20497-  }
20498-
20499-  /************************************
20500-   Floating-point helpers
20501-   ************************************/
20502-
20503-  // The floating-point helper functions and implementation
20504-  // borrows heavily from sinful.js: http://guipn.github.io/sinful.js/
20505-
20506-  /**
20507-   * Array.prototype.reduce for browsers that don't support it
20508-   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Compatibility
20509-   */
20510-  if ('function' !== typeof Array.prototype.reduce) {
20511-    Array.prototype.reduce = function (callback, opt_initialValue) {
20512-      'use strict';
20513-
20514-      if (null === this || 'undefined' === typeof this) {
20515-        // At the moment all modern browsers, that support strict mode, have
20516-        // native implementation of Array.prototype.reduce. For instance, IE8
20517-        // does not support strict mode, so this check is actually useless.
20518-        throw new TypeError('Array.prototype.reduce called on null or undefined');
20519-      }
20520-
20521-      if ('function' !== typeof callback) {
20522-        throw new TypeError(callback + ' is not a function');
20523-      }
20524-
20525-      var index,
20526-        value,
20527-        length = this.length >>> 0,
20528-        isValueSet = false;
20529-
20530-      if (1 < arguments.length) {
20531-        value = opt_initialValue;
20532-        isValueSet = true;
20533-      }
20534-
20535-      for (index = 0; length > index; ++index) {
20536-        if (this.hasOwnProperty(index)) {
20537-          if (isValueSet) {
20538-            value = callback(value, this[index], index, this);
20539-          } else {
20540-            value = this[index];
20541-            isValueSet = true;
20542-          }
20543-        }
20544-      }
20545-
20546-      if (!isValueSet) {
20547-        throw new TypeError('Reduce of empty array with no initial value');
20548-      }
20549-
20550-      return value;
20551-    };
20552-  }
20553-
20554-
20555-  /**
20556-   * Computes the multiplier necessary to make x >= 1,
20557-   * effectively eliminating miscalculations caused by
20558-   * finite precision.
20559-   */
20560-  function multiplier(x) {
20561-    var parts = x.toString().split('.');
20562-    if (parts.length < 2) {
20563-      return 1;
20564-    }
20565-    return Math.pow(10, parts[1].length);
20566-  }
20567-
20568-  /**
20569-   * Given a variable number of arguments, returns the maximum
20570-   * multiplier that must be used to normalize an operation involving
20571-   * all of them.
20572-   */
20573-  function correctionFactor() {
20574-    var args = Array.prototype.slice.call(arguments);
20575-    return args.reduce(function (prev, next) {
20576-      var mp = multiplier(prev),
20577-        mn = multiplier(next);
20578-      return mp > mn ? mp : mn;
20579-    }, -Infinity);
20580-  }
20581-
20582-
20583-  /************************************
20584-   Numeral Prototype
20585-   ************************************/
20586-
20587-
20588-  numeral.fn = Numeral.prototype = {
20589-
20590-    clone : function () {
20591-      return numeral(this);
20592-    },
20593-
20594-    format : function (inputString, roundingFunction) {
20595-      return formatNumeral(this,
20596-        inputString ? inputString : defaultFormat,
20597-        (roundingFunction !== undefined) ? roundingFunction : Math.round
20598-      );
20599-    },
20600-
20601-    unformat : function (inputString) {
20602-      if (Object.prototype.toString.call(inputString) === '[object Number]') {
20603-        return inputString;
20604-      }
20605-      return unformatNumeral(this, inputString ? inputString : defaultFormat);
20606-    },
20607-
20608-    value : function () {
20609-      return this._value;
20610-    },
20611-
20612-    valueOf : function () {
20613-      return this._value;
20614-    },
20615-
20616-    set : function (value) {
20617-      this._value = Number(value);
20618-      return this;
20619-    },
20620-
20621-    add : function (value) {
20622-      var corrFactor = correctionFactor.call(null, this._value, value);
20623-      function cback(accum, curr, currI, O) {
20624-        return accum + corrFactor * curr;
20625-      }
20626-      this._value = [this._value, value].reduce(cback, 0) / corrFactor;
20627-      return this;
20628-    },
20629-
20630-    subtract : function (value) {
20631-      var corrFactor = correctionFactor.call(null, this._value, value);
20632-      function cback(accum, curr, currI, O) {
20633-        return accum - corrFactor * curr;
20634-      }
20635-      this._value = [value].reduce(cback, this._value * corrFactor) / corrFactor;
20636-      return this;
20637-    },
20638-
20639-    multiply : function (value) {
20640-      function cback(accum, curr, currI, O) {
20641-        var corrFactor = correctionFactor(accum, curr);
20642-        return (accum * corrFactor) * (curr * corrFactor) /
20643-          (corrFactor * corrFactor);
20644-      }
20645-      this._value = [this._value, value].reduce(cback, 1);
20646-      return this;
20647-    },
20648-
20649-    divide : function (value) {
20650-      function cback(accum, curr, currI, O) {
20651-        var corrFactor = correctionFactor(accum, curr);
20652-        return (accum * corrFactor) / (curr * corrFactor);
20653-      }
20654-      this._value = [this._value, value].reduce(cback);
20655-      return this;
20656-    },
20657-
20658-    difference : function (value) {
20659-      return Math.abs(numeral(this._value).subtract(value).value());
20660-    }
20661-
20662-  };
20663-
20664-  /************************************
20665-   Exposing Numeral
20666-   ************************************/
20667-
20668-  // CommonJS module is defined
20669-  if (hasModule) {
20670-    module.exports = numeral;
20671-  }
20672-
20673-  /*global ender:false */
20674-  if (typeof ender === 'undefined') {
20675-    // here, `this` means `window` in the browser, or `global` on the server
20676-    // add `numeral` as a global object via a string identifier,
20677-    // for Closure Compiler 'advanced' mode
20678-    this['numeral'] = numeral;
20679-  }
20680-
20681-  /*global define:false */
20682-  if (typeof define === 'function' && define.amd) {
20683-    define([], function () {
20684-      return numeral;
20685-    });
20686-  }
20687-}).call(this);
20688diff --git a/lib/numericjs/numeric.js b/lib/numericjs/numeric.js
20689deleted file mode 100644
20690index 86becd7..0000000
20691--- a/lib/numericjs/numeric.js
20692+++ /dev/null
20693@@ -1,3263 +0,0 @@
20694-"use strict";
20695-
20696-var numeric = (typeof exports === "undefined")?(function numeric() {}):(exports);
20697-if(typeof global !== "undefined") { global.numeric = numeric; }
20698-
20699-numeric.version = "1.2.6";
20700-
20701-// 1. Utility functions
20702-numeric.bench = function bench (f,interval) {
20703-  var t1,t2,n,i;
20704-  if(typeof interval === "undefined") { interval = 15; }
20705-  n = 0.5;
20706-  t1 = new Date();
20707-  while(1) {
20708-    n*=2;
20709-    for(i=n;i>3;i-=4) { f(); f(); f(); f(); }
20710-    while(i>0) { f(); i--; }
20711-    t2 = new Date();
20712-    if(t2-t1 > interval) break;
20713-  }
20714-  for(i=n;i>3;i-=4) { f(); f(); f(); f(); }
20715-  while(i>0) { f(); i--; }
20716-  t2 = new Date();
20717-  return 1000*(3*n-1)/(t2-t1);
20718-}
20719-
20720-numeric._myIndexOf = (function _myIndexOf(w) {
20721-  var n = this.length,k;
20722-  for(k=0;k<n;++k) if(this[k]===w) return k;
20723-  return -1;
20724-});
20725-numeric.myIndexOf = (Array.prototype.indexOf)?Array.prototype.indexOf:numeric._myIndexOf;
20726-
20727-numeric.Function = Function;
20728-numeric.precision = 4;
20729-numeric.largeArray = 50;
20730-
20731-numeric.prettyPrint = function prettyPrint(x) {
20732-  function fmtnum(x) {
20733-    if(x === 0) { return '0'; }
20734-    if(isNaN(x)) { return 'NaN'; }
20735-    if(x<0) { return '-'+fmtnum(-x); }
20736-    if(isFinite(x)) {
20737-      var scale = Math.floor(Math.log(x) / Math.log(10));
20738-      var normalized = x / Math.pow(10,scale);
20739-      var basic = normalized.toPrecision(numeric.precision);
20740-      if(parseFloat(basic) === 10) { scale++; normalized = 1; basic = normalized.toPrecision(numeric.precision); }
20741-      return parseFloat(basic).toString()+'e'+scale.toString();
20742-    }
20743-    return 'Infinity';
20744-  }
20745-  var ret = [];
20746-  function foo(x) {
20747-    var k;
20748-    if(typeof x === "undefined") { ret.push(Array(numeric.precision+8).join(' ')); return false; }
20749-    if(typeof x === "string") { ret.push('"'+x+'"'); return false; }
20750-    if(typeof x === "boolean") { ret.push(x.toString()); return false; }
20751-    if(typeof x === "number") {
20752-      var a = fmtnum(x);
20753-      var b = x.toPrecision(numeric.precision);
20754-      var c = parseFloat(x.toString()).toString();
20755-      var d = [a,b,c,parseFloat(b).toString(),parseFloat(c).toString()];
20756-      for(k=1;k<d.length;k++) { if(d[k].length < a.length) a = d[k]; }
20757-      ret.push(Array(numeric.precision+8-a.length).join(' ')+a);
20758-      return false;
20759-    }
20760-    if(x === null) { ret.push("null"); return false; }
20761-    if(typeof x === "function") {
20762-      ret.push(x.toString());
20763-      var flag = false;
20764-      for(k in x) { if(x.hasOwnProperty(k)) {
20765-        if(flag) ret.push(',\n');
20766-        else ret.push('\n{');
20767-        flag = true;
20768-        ret.push(k);
20769-        ret.push(': \n');
20770-        foo(x[k]);
20771-      } }
20772-      if(flag) ret.push('}\n');
20773-      return true;
20774-    }
20775-    if(x instanceof Array) {
20776-      if(x.length > numeric.largeArray) { ret.push('...Large Array...'); return true; }
20777-      var flag = false;
20778-      ret.push('[');
20779-      for(k=0;k<x.length;k++) { if(k>0) { ret.push(','); if(flag) ret.push('\n '); } flag = foo(x[k]); }
20780-      ret.push(']');
20781-      return true;
20782-    }
20783-    ret.push('{');
20784-    var flag = false;
20785-    for(k in x) { if(x.hasOwnProperty(k)) { if(flag) ret.push(',\n'); flag = true; ret.push(k); ret.push(': \n'); foo(x[k]); } }
20786-    ret.push('}');
20787-    return true;
20788-  }
20789-  foo(x);
20790-  return ret.join('');
20791-}
20792-
20793-numeric.parseDate = function parseDate(d) {
20794-  function foo(d) {
20795-    if(typeof d === 'string') { return Date.parse(d.replace(/-/g,'/')); }
20796-    if(!(d instanceof Array)) { throw new Error("parseDate: parameter must be arrays of strings"); }
20797-    var ret = [],k;
20798-    for(k=0;k<d.length;k++) { ret[k] = foo(d[k]); }
20799-    return ret;
20800-  }
20801-  return foo(d);
20802-}
20803-
20804-numeric.parseFloat = function parseFloat_(d) {
20805-  function foo(d) {
20806-    if(typeof d === 'string') { return parseFloat(d); }
20807-    if(!(d instanceof Array)) { throw new Error("parseFloat: parameter must be arrays of strings"); }
20808-    var ret = [],k;
20809-    for(k=0;k<d.length;k++) { ret[k] = foo(d[k]); }
20810-    return ret;
20811-  }
20812-  return foo(d);
20813-}
20814-
20815-numeric.parseCSV = function parseCSV(t) {
20816-  var foo = t.split('\n');
20817-  var j,k;
20818-  var ret = [];
20819-  var pat = /(([^'",]*)|('[^']*')|("[^"]*")),/g;
20820-  var patnum = /^\s*(([+-]?[0-9]+(\.[0-9]*)?(e[+-]?[0-9]+)?)|([+-]?[0-9]*(\.[0-9]+)?(e[+-]?[0-9]+)?))\s*$/;
20821-  var stripper = function(n) { return n.substr(0,n.length-1); }
20822-  var count = 0;
20823-  for(k=0;k<foo.length;k++) {
20824-    var bar = (foo[k]+",").match(pat),baz;
20825-    if(bar.length>0) {
20826-      ret[count] = [];
20827-      for(j=0;j<bar.length;j++) {
20828-        baz = stripper(bar[j]);
20829-        if(patnum.test(baz)) { ret[count][j] = parseFloat(baz); }
20830-        else ret[count][j] = baz;
20831-      }
20832-      count++;
20833-    }
20834-  }
20835-  return ret;
20836-}
20837-
20838-numeric.toCSV = function toCSV(A) {
20839-  var s = numeric.dim(A);
20840-  var i,j,m,n,row,ret;
20841-  m = s[0];
20842-  n = s[1];
20843-  ret = [];
20844-  for(i=0;i<m;i++) {
20845-    row = [];
20846-    for(j=0;j<m;j++) { row[j] = A[i][j].toString(); }
20847-    ret[i] = row.join(', ');
20848-  }
20849-  return ret.join('\n')+'\n';
20850-}
20851-
20852-numeric.getURL = function getURL(url) {
20853-  var client = new XMLHttpRequest();
20854-  client.open("GET",url,false);
20855-  client.send();
20856-  return client;
20857-}
20858-
20859-numeric.imageURL = function imageURL(img) {
20860-  function base64(A) {
20861-    var n = A.length, i,x,y,z,p,q,r,s;
20862-    var key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
20863-    var ret = "";
20864-    for(i=0;i<n;i+=3) {
20865-      x = A[i];
20866-      y = A[i+1];
20867-      z = A[i+2];
20868-      p = x >> 2;
20869-      q = ((x & 3) << 4) + (y >> 4);
20870-      r = ((y & 15) << 2) + (z >> 6);
20871-      s = z & 63;
20872-      if(i+1>=n) { r = s = 64; }
20873-      else if(i+2>=n) { s = 64; }
20874-      ret += key.charAt(p) + key.charAt(q) + key.charAt(r) + key.charAt(s);
20875-    }
20876-    return ret;
20877-  }
20878-  function crc32Array (a,from,to) {
20879-    if(typeof from === "undefined") { from = 0; }
20880-    if(typeof to === "undefined") { to = a.length; }
20881-    var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
20882-      0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
20883-      0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
20884-      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
20885-      0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
20886-      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
20887-      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
20888-      0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
20889-      0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
20890-      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
20891-      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
20892-      0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
20893-      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
20894-      0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
20895-      0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
20896-      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
20897-      0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
20898-      0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
20899-      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
20900-      0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
20901-      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
20902-      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
20903-      0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
20904-      0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
20905-      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
20906-      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
20907-      0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
20908-      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
20909-      0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
20910-      0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
20911-      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
20912-      0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D];
20913-
20914-    var crc = -1, y = 0, n = a.length,i;
20915-
20916-    for (i = from; i < to; i++) {
20917-      y = (crc ^ a[i]) & 0xFF;
20918-      crc = (crc >>> 8) ^ table[y];
20919-    }
20920-
20921-    return crc ^ (-1);
20922-  }
20923-
20924-  var h = img[0].length, w = img[0][0].length, s1, s2, next,k,length,a,b,i,j,adler32,crc32;
20925-  var stream = [
20926-    137, 80, 78, 71, 13, 10, 26, 10,                           //  0: PNG signature
20927-    0,0,0,13,                                                  //  8: IHDR Chunk length
20928-    73, 72, 68, 82,                                            // 12: "IHDR"
20929-    (w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w&255,   // 16: Width
20930-    (h >> 24) & 255, (h >> 16) & 255, (h >> 8) & 255, h&255,   // 20: Height
20931-    8,                                                         // 24: bit depth
20932-    2,                                                         // 25: RGB
20933-    0,                                                         // 26: deflate
20934-    0,                                                         // 27: no filter
20935-    0,                                                         // 28: no interlace
20936-    -1,-2,-3,-4,                                               // 29: CRC
20937-    -5,-6,-7,-8,                                               // 33: IDAT Chunk length
20938-    73, 68, 65, 84,                                            // 37: "IDAT"
20939-    // RFC 1950 header starts here
20940-    8,                                                         // 41: RFC1950 CMF
20941-    29                                                         // 42: RFC1950 FLG
20942-  ];
20943-  crc32 = crc32Array(stream,12,29);
20944-  stream[29] = (crc32>>24)&255;
20945-  stream[30] = (crc32>>16)&255;
20946-  stream[31] = (crc32>>8)&255;
20947-  stream[32] = (crc32)&255;
20948-  s1 = 1;
20949-  s2 = 0;
20950-  for(i=0;i<h;i++) {
20951-    if(i<h-1) { stream.push(0); }
20952-    else { stream.push(1); }
20953-    a = (3*w+1+(i===0))&255; b = ((3*w+1+(i===0))>>8)&255;
20954-    stream.push(a); stream.push(b);
20955-    stream.push((~a)&255); stream.push((~b)&255);
20956-    if(i===0) stream.push(0);
20957-    for(j=0;j<w;j++) {
20958-      for(k=0;k<3;k++) {
20959-        a = img[k][i][j];
20960-        if(a>255) a = 255;
20961-        else if(a<0) a=0;
20962-        else a = Math.round(a);
20963-        s1 = (s1 + a )%65521;
20964-        s2 = (s2 + s1)%65521;
20965-        stream.push(a);
20966-      }
20967-    }
20968-    stream.push(0);
20969-  }
20970-  adler32 = (s2<<16)+s1;
20971-  stream.push((adler32>>24)&255);
20972-  stream.push((adler32>>16)&255);
20973-  stream.push((adler32>>8)&255);
20974-  stream.push((adler32)&255);
20975-  length = stream.length - 41;
20976-  stream[33] = (length>>24)&255;
20977-  stream[34] = (length>>16)&255;
20978-  stream[35] = (length>>8)&255;
20979-  stream[36] = (length)&255;
20980-  crc32 = crc32Array(stream,37);
20981-  stream.push((crc32>>24)&255);
20982-  stream.push((crc32>>16)&255);
20983-  stream.push((crc32>>8)&255);
20984-  stream.push((crc32)&255);
20985-  stream.push(0);
20986-  stream.push(0);
20987-  stream.push(0);
20988-  stream.push(0);
20989-//    a = stream.length;
20990-  stream.push(73);  // I
20991-  stream.push(69);  // E
20992-  stream.push(78);  // N
20993-  stream.push(68);  // D
20994-  stream.push(174); // CRC1
20995-  stream.push(66);  // CRC2
20996-  stream.push(96);  // CRC3
20997-  stream.push(130); // CRC4
20998-  return 'data:image/png;base64,'+base64(stream);
20999-}
21000-
21001-// 2. Linear algebra with Arrays.
21002-numeric._dim = function _dim(x) {
21003-  var ret = [];
21004-  while(typeof x === "object") { ret.push(x.length); x = x[0]; }
21005-  return ret;
21006-}
21007-
21008-numeric.dim = function dim(x) {
21009-  var y,z;
21010-  if(typeof x === "object") {
21011-    y = x[0];
21012-    if(typeof y === "object") {
21013-      z = y[0];
21014-      if(typeof z === "object") {
21015-        return numeric._dim(x);
21016-      }
21017-      return [x.length,y.length];
21018-    }
21019-    return [x.length];
21020-  }
21021-  return [];
21022-}
21023-
21024-numeric.mapreduce = function mapreduce(body,init) {
21025-  return Function('x','accum','_s','_k',
21026-    'if(typeof accum === "undefined") accum = '+init+';\n'+
21027-    'if(typeof x === "number") { var xi = x; '+body+'; return accum; }\n'+
21028-    'if(typeof _s === "undefined") _s = numeric.dim(x);\n'+
21029-    'if(typeof _k === "undefined") _k = 0;\n'+
21030-    'var _n = _s[_k];\n'+
21031-    'var i,xi;\n'+
21032-    'if(_k < _s.length-1) {\n'+
21033-    '    for(i=_n-1;i>=0;i--) {\n'+
21034-    '        accum = arguments.callee(x[i],accum,_s,_k+1);\n'+
21035-    '    }'+
21036-    '    return accum;\n'+
21037-    '}\n'+
21038-    'for(i=_n-1;i>=1;i-=2) { \n'+
21039-    '    xi = x[i];\n'+
21040-    '    '+body+';\n'+
21041-    '    xi = x[i-1];\n'+
21042-    '    '+body+';\n'+
21043-    '}\n'+
21044-    'if(i === 0) {\n'+
21045-    '    xi = x[i];\n'+
21046-    '    '+body+'\n'+
21047-    '}\n'+
21048-    'return accum;'
21049-  );
21050-}
21051-numeric.mapreduce2 = function mapreduce2(body,setup) {
21052-  return Function('x',
21053-    'var n = x.length;\n'+
21054-    'var i,xi;\n'+setup+';\n'+
21055-    'for(i=n-1;i!==-1;--i) { \n'+
21056-    '    xi = x[i];\n'+
21057-    '    '+body+';\n'+
21058-    '}\n'+
21059-    'return accum;'
21060-  );
21061-}
21062-
21063-
21064-numeric.same = function same(x,y) {
21065-  var i,n;
21066-  if(!(x instanceof Array) || !(y instanceof Array)) { return false; }
21067-  n = x.length;
21068-  if(n !== y.length) { return false; }
21069-  for(i=0;i<n;i++) {
21070-    if(x[i] === y[i]) { continue; }
21071-    if(typeof x[i] === "object") { if(!same(x[i],y[i])) return false; }
21072-    else { return false; }
21073-  }
21074-  return true;
21075-}
21076-
21077-numeric.rep = function rep(s,v,k) {
21078-  if(typeof k === "undefined") { k=0; }
21079-  var n = s[k], ret = Array(n), i;
21080-  if(k === s.length-1) {
21081-    for(i=n-2;i>=0;i-=2) { ret[i+1] = v; ret[i] = v; }
21082-    if(i===-1) { ret[0] = v; }
21083-    return ret;
21084-  }
21085-  for(i=n-1;i>=0;i--) { ret[i] = numeric.rep(s,v,k+1); }
21086-  return ret;
21087-}
21088-
21089-
21090-numeric.dotMMsmall = function dotMMsmall(x,y) {
21091-  var i,j,k,p,q,r,ret,foo,bar,woo,i0,k0,p0,r0;
21092-  p = x.length; q = y.length; r = y[0].length;
21093-  ret = Array(p);
21094-  for(i=p-1;i>=0;i--) {
21095-    foo = Array(r);
21096-    bar = x[i];
21097-    for(k=r-1;k>=0;k--) {
21098-      woo = bar[q-1]*y[q-1][k];
21099-      for(j=q-2;j>=1;j-=2) {
21100-        i0 = j-1;
21101-        woo += bar[j]*y[j][k] + bar[i0]*y[i0][k];
21102-      }
21103-      if(j===0) { woo += bar[0]*y[0][k]; }
21104-      foo[k] = woo;
21105-    }
21106-    ret[i] = foo;
21107-  }
21108-  return ret;
21109-}
21110-numeric._getCol = function _getCol(A,j,x) {
21111-  var n = A.length, i;
21112-  for(i=n-1;i>0;--i) {
21113-    x[i] = A[i][j];
21114-    --i;
21115-    x[i] = A[i][j];
21116-  }
21117-  if(i===0) x[0] = A[0][j];
21118-}
21119-numeric.dotMMbig = function dotMMbig(x,y){
21120-  var gc = numeric._getCol, p = y.length, v = Array(p);
21121-  var m = x.length, n = y[0].length, A = new Array(m), xj;
21122-  var VV = numeric.dotVV;
21123-  var i,j,k,z;
21124-  --p;
21125-  --m;
21126-  for(i=m;i!==-1;--i) A[i] = Array(n);
21127-  --n;
21128-  for(i=n;i!==-1;--i) {
21129-    gc(y,i,v);
21130-    for(j=m;j!==-1;--j) {
21131-      z=0;
21132-      xj = x[j];
21133-      A[j][i] = VV(xj,v);
21134-    }
21135-  }
21136-  return A;
21137-}
21138-
21139-numeric.dotMV = function dotMV(x,y) {
21140-  var p = x.length, q = y.length,i;
21141-  var ret = Array(p), dotVV = numeric.dotVV;
21142-  for(i=p-1;i>=0;i--) { ret[i] = dotVV(x[i],y); }
21143-  return ret;
21144-}
21145-
21146-numeric.dotVM = function dotVM(x,y) {
21147-  var i,j,k,p,q,r,ret,foo,bar,woo,i0,k0,p0,r0,s1,s2,s3,baz,accum;
21148-  p = x.length; q = y[0].length;
21149-  ret = Array(q);
21150-  for(k=q-1;k>=0;k--) {
21151-    woo = x[p-1]*y[p-1][k];
21152-    for(j=p-2;j>=1;j-=2) {
21153-      i0 = j-1;
21154-      woo += x[j]*y[j][k] + x[i0]*y[i0][k];
21155-    }
21156-    if(j===0) { woo += x[0]*y[0][k]; }
21157-    ret[k] = woo;
21158-  }
21159-  return ret;
21160-}
21161-
21162-numeric.dotVV = function dotVV(x,y) {
21163-  var i,n=x.length,i1,ret = x[n-1]*y[n-1];
21164-  for(i=n-2;i>=1;i-=2) {
21165-    i1 = i-1;
21166-    ret += x[i]*y[i] + x[i1]*y[i1];
21167-  }
21168-  if(i===0) { ret += x[0]*y[0]; }
21169-  return ret;
21170-}
21171-
21172-numeric.dot = function dot(x,y) {
21173-  var d = numeric.dim;
21174-  switch(d(x).length*1000+d(y).length) {
21175-    case 2002:
21176-      if(y.length < 10) return numeric.dotMMsmall(x,y);
21177-      else return numeric.dotMMbig(x,y);
21178-    case 2001: return numeric.dotMV(x,y);
21179-    case 1002: return numeric.dotVM(x,y);
21180-    case 1001: return numeric.dotVV(x,y);
21181-    case 1000: return numeric.mulVS(x,y);
21182-    case 1: return numeric.mulSV(x,y);
21183-    case 0: return x*y;
21184-    default: throw new Error('numeric.dot only works on vectors and matrices');
21185-  }
21186-}
21187-
21188-numeric.diag = function diag(d) {
21189-  var i,i1,j,n = d.length, A = Array(n), Ai;
21190-  for(i=n-1;i>=0;i--) {
21191-    Ai = Array(n);
21192-    i1 = i+2;
21193-    for(j=n-1;j>=i1;j-=2) {
21194-      Ai[j] = 0;
21195-      Ai[j-1] = 0;
21196-    }
21197-    if(j>i) { Ai[j] = 0; }
21198-    Ai[i] = d[i];
21199-    for(j=i-1;j>=1;j-=2) {
21200-      Ai[j] = 0;
21201-      Ai[j-1] = 0;
21202-    }
21203-    if(j===0) { Ai[0] = 0; }
21204-    A[i] = Ai;
21205-  }
21206-  return A;
21207-}
21208-numeric.getDiag = function(A) {
21209-  var n = Math.min(A.length,A[0].length),i,ret = Array(n);
21210-  for(i=n-1;i>=1;--i) {
21211-    ret[i] = A[i][i];
21212-    --i;
21213-    ret[i] = A[i][i];
21214-  }
21215-  if(i===0) {
21216-    ret[0] = A[0][0];
21217-  }
21218-  return ret;
21219-}
21220-
21221-numeric.identity = function identity(n) { return numeric.diag(numeric.rep([n],1)); }
21222-numeric.pointwise = function pointwise(params,body,setup) {
21223-  if(typeof setup === "undefined") { setup = ""; }
21224-  var fun = [];
21225-  var k;
21226-  var avec = /\[i\]$/,p,thevec = '';
21227-  var haveret = false;
21228-  for(k=0;k<params.length;k++) {
21229-    if(avec.test(params[k])) {
21230-      p = params[k].substring(0,params[k].length-3);
21231-      thevec = p;
21232-    } else { p = params[k]; }
21233-    if(p==='ret') haveret = true;
21234-    fun.push(p);
21235-  }
21236-  fun[params.length] = '_s';
21237-  fun[params.length+1] = '_k';
21238-  fun[params.length+2] = (
21239-    'if(typeof _s === "undefined") _s = numeric.dim('+thevec+');\n'+
21240-    'if(typeof _k === "undefined") _k = 0;\n'+
21241-    'var _n = _s[_k];\n'+
21242-    'var i'+(haveret?'':', ret = Array(_n)')+';\n'+
21243-    'if(_k < _s.length-1) {\n'+
21244-    '    for(i=_n-1;i>=0;i--) ret[i] = arguments.callee('+params.join(',')+',_s,_k+1);\n'+
21245-    '    return ret;\n'+
21246-    '}\n'+
21247-    setup+'\n'+
21248-    'for(i=_n-1;i!==-1;--i) {\n'+
21249-    '    '+body+'\n'+
21250-    '}\n'+
21251-    'return ret;'
21252-  );
21253-  return Function.apply(null,fun);
21254-}
21255-numeric.pointwise2 = function pointwise2(params,body,setup) {
21256-  if(typeof setup === "undefined") { setup = ""; }
21257-  var fun = [];
21258-  var k;
21259-  var avec = /\[i\]$/,p,thevec = '';
21260-  var haveret = false;
21261-  for(k=0;k<params.length;k++) {
21262-    if(avec.test(params[k])) {
21263-      p = params[k].substring(0,params[k].length-3);
21264-      thevec = p;
21265-    } else { p = params[k]; }
21266-    if(p==='ret') haveret = true;
21267-    fun.push(p);
21268-  }
21269-  fun[params.length] = (
21270-    'var _n = '+thevec+'.length;\n'+
21271-    'var i'+(haveret?'':', ret = Array(_n)')+';\n'+
21272-    setup+'\n'+
21273-    'for(i=_n-1;i!==-1;--i) {\n'+
21274-    body+'\n'+
21275-    '}\n'+
21276-    'return ret;'
21277-  );
21278-  return Function.apply(null,fun);
21279-}
21280-numeric._biforeach = (function _biforeach(x,y,s,k,f) {
21281-  if(k === s.length-1) { f(x,y); return; }
21282-  var i,n=s[k];
21283-  for(i=n-1;i>=0;i--) { _biforeach(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); }
21284-});
21285-numeric._biforeach2 = (function _biforeach2(x,y,s,k,f) {
21286-  if(k === s.length-1) { return f(x,y); }
21287-  var i,n=s[k],ret = Array(n);
21288-  for(i=n-1;i>=0;--i) { ret[i] = _biforeach2(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); }
21289-  return ret;
21290-});
21291-numeric._foreach = (function _foreach(x,s,k,f) {
21292-  if(k === s.length-1) { f(x); return; }
21293-  var i,n=s[k];
21294-  for(i=n-1;i>=0;i--) { _foreach(x[i],s,k+1,f); }
21295-});
21296-numeric._foreach2 = (function _foreach2(x,s,k,f) {
21297-  if(k === s.length-1) { return f(x); }
21298-  var i,n=s[k], ret = Array(n);
21299-  for(i=n-1;i>=0;i--) { ret[i] = _foreach2(x[i],s,k+1,f); }
21300-  return ret;
21301-});
21302-
21303-/*numeric.anyV = numeric.mapreduce('if(xi) return true;','false');
21304- numeric.allV = numeric.mapreduce('if(!xi) return false;','true');
21305- numeric.any = function(x) { if(typeof x.length === "undefined") return x; return numeric.anyV(x); }
21306- numeric.all = function(x) { if(typeof x.length === "undefined") return x; return numeric.allV(x); }*/
21307-
21308-numeric.ops2 = {
21309-  add: '+',
21310-  sub: '-',
21311-  mul: '*',
21312-  div: '/',
21313-  mod: '%',
21314-  and: '&&',
21315-  or:  '||',
21316-  eq:  '===',
21317-  neq: '!==',
21318-  lt:  '<',
21319-  gt:  '>',
21320-  leq: '<=',
21321-  geq: '>=',
21322-  band: '&',
21323-  bor: '|',
21324-  bxor: '^',
21325-  lshift: '<<',
21326-  rshift: '>>',
21327-  rrshift: '>>>'
21328-};
21329-numeric.opseq = {
21330-  addeq: '+=',
21331-  subeq: '-=',
21332-  muleq: '*=',
21333-  diveq: '/=',
21334-  modeq: '%=',
21335-  lshifteq: '<<=',
21336-  rshifteq: '>>=',
21337-  rrshifteq: '>>>=',
21338-  bandeq: '&=',
21339-  boreq: '|=',
21340-  bxoreq: '^='
21341-};
21342-numeric.mathfuns = ['abs','acos','asin','atan','ceil','cos',
21343-  'exp','floor','log','round','sin','sqrt','tan',
21344-  'isNaN','isFinite'];
21345-numeric.mathfuns2 = ['atan2','pow','max','min'];
21346-numeric.ops1 = {
21347-  neg: '-',
21348-  not: '!',
21349-  bnot: '~',
21350-  clone: ''
21351-};
21352-numeric.mapreducers = {
21353-  any: ['if(xi) return true;','var accum = false;'],
21354-  all: ['if(!xi) return false;','var accum = true;'],
21355-  sum: ['accum += xi;','var accum = 0;'],
21356-  prod: ['accum *= xi;','var accum = 1;'],
21357-  norm2Squared: ['accum += xi*xi;','var accum = 0;'],
21358-  norminf: ['accum = max(accum,abs(xi));','var accum = 0, max = Math.max, abs = Math.abs;'],
21359-  norm1: ['accum += abs(xi)','var accum = 0, abs = Math.abs;'],
21360-  sup: ['accum = max(accum,xi);','var accum = -Infinity, max = Math.max;'],
21361-  inf: ['accum = min(accum,xi);','var accum = Infinity, min = Math.min;']
21362-};
21363-
21364-(function () {
21365-  var i,o;
21366-  for(i=0;i<numeric.mathfuns2.length;++i) {
21367-    o = numeric.mathfuns2[i];
21368-    numeric.ops2[o] = o;
21369-  }
21370-  for(i in numeric.ops2) {
21371-    if(numeric.ops2.hasOwnProperty(i)) {
21372-      o = numeric.ops2[i];
21373-      var code, codeeq, setup = '';
21374-      if(numeric.myIndexOf.call(numeric.mathfuns2,i)!==-1) {
21375-        setup = 'var '+o+' = Math.'+o+';\n';
21376-        code = function(r,x,y) { return r+' = '+o+'('+x+','+y+')'; };
21377-        codeeq = function(x,y) { return x+' = '+o+'('+x+','+y+')'; };
21378-      } else {
21379-        code = function(r,x,y) { return r+' = '+x+' '+o+' '+y; };
21380-        if(numeric.opseq.hasOwnProperty(i+'eq')) {
21381-          codeeq = function(x,y) { return x+' '+o+'= '+y; };
21382-        } else {
21383-          codeeq = function(x,y) { return x+' = '+x+' '+o+' '+y; };
21384-        }
21385-      }
21386-      numeric[i+'VV'] = numeric.pointwise2(['x[i]','y[i]'],code('ret[i]','x[i]','y[i]'),setup);
21387-      numeric[i+'SV'] = numeric.pointwise2(['x','y[i]'],code('ret[i]','x','y[i]'),setup);
21388-      numeric[i+'VS'] = numeric.pointwise2(['x[i]','y'],code('ret[i]','x[i]','y'),setup);
21389-      numeric[i] = Function(
21390-        'var n = arguments.length, i, x = arguments[0], y;\n'+
21391-        'var VV = numeric.'+i+'VV, VS = numeric.'+i+'VS, SV = numeric.'+i+'SV;\n'+
21392-        'var dim = numeric.dim;\n'+
21393-        'for(i=1;i!==n;++i) { \n'+
21394-        '  y = arguments[i];\n'+
21395-        '  if(typeof x === "object") {\n'+
21396-        '      if(typeof y === "object") x = numeric._biforeach2(x,y,dim(x),0,VV);\n'+
21397-        '      else x = numeric._biforeach2(x,y,dim(x),0,VS);\n'+
21398-        '  } else if(typeof y === "object") x = numeric._biforeach2(x,y,dim(y),0,SV);\n'+
21399-        '  else '+codeeq('x','y')+'\n'+
21400-        '}\nreturn x;\n');
21401-      numeric[o] = numeric[i];
21402-      numeric[i+'eqV'] = numeric.pointwise2(['ret[i]','x[i]'], codeeq('ret[i]','x[i]'),setup);
21403-      numeric[i+'eqS'] = numeric.pointwise2(['ret[i]','x'], codeeq('ret[i]','x'),setup);
21404-      numeric[i+'eq'] = Function(
21405-        'var n = arguments.length, i, x = arguments[0], y;\n'+
21406-        'var V = numeric.'+i+'eqV, S = numeric.'+i+'eqS\n'+
21407-        'var s = numeric.dim(x);\n'+
21408-        'for(i=1;i!==n;++i) { \n'+
21409-        '  y = arguments[i];\n'+
21410-        '  if(typeof y === "object") numeric._biforeach(x,y,s,0,V);\n'+
21411-        '  else numeric._biforeach(x,y,s,0,S);\n'+
21412-        '}\nreturn x;\n');
21413-    }
21414-  }
21415-  for(i=0;i<numeric.mathfuns2.length;++i) {
21416-    o = numeric.mathfuns2[i];
21417-    delete numeric.ops2[o];
21418-  }
21419-  for(i=0;i<numeric.mathfuns.length;++i) {
21420-    o = numeric.mathfuns[i];
21421-    numeric.ops1[o] = o;
21422-  }
21423-  for(i in numeric.ops1) {
21424-    if(numeric.ops1.hasOwnProperty(i)) {
21425-      setup = '';
21426-      o = numeric.ops1[i];
21427-      if(numeric.myIndexOf.call(numeric.mathfuns,i)!==-1) {
21428-        if(Math.hasOwnProperty(o)) setup = 'var '+o+' = Math.'+o+';\n';
21429-      }
21430-      numeric[i+'eqV'] = numeric.pointwise2(['ret[i]'],'ret[i] = '+o+'(ret[i]);',setup);
21431-      numeric[i+'eq'] = Function('x',
21432-        'if(typeof x !== "object") return '+o+'x\n'+
21433-        'var i;\n'+
21434-        'var V = numeric.'+i+'eqV;\n'+
21435-        'var s = numeric.dim(x);\n'+
21436-        'numeric._foreach(x,s,0,V);\n'+
21437-        'return x;\n');
21438-      numeric[i+'V'] = numeric.pointwise2(['x[i]'],'ret[i] = '+o+'(x[i]);',setup);
21439-      numeric[i] = Function('x',
21440-        'if(typeof x !== "object") return '+o+'(x)\n'+
21441-        'var i;\n'+
21442-        'var V = numeric.'+i+'V;\n'+
21443-        'var s = numeric.dim(x);\n'+
21444-        'return numeric._foreach2(x,s,0,V);\n');
21445-    }
21446-  }
21447-  for(i=0;i<numeric.mathfuns.length;++i) {
21448-    o = numeric.mathfuns[i];
21449-    delete numeric.ops1[o];
21450-  }
21451-  for(i in numeric.mapreducers) {
21452-    if(numeric.mapreducers.hasOwnProperty(i)) {
21453-      o = numeric.mapreducers[i];
21454-      numeric[i+'V'] = numeric.mapreduce2(o[0],o[1]);
21455-      numeric[i] = Function('x','s','k',
21456-        o[1]+
21457-        'if(typeof x !== "object") {'+
21458-        '    xi = x;\n'+
21459-        o[0]+';\n'+
21460-        '    return accum;\n'+
21461-        '}'+
21462-        'if(typeof s === "undefined") s = numeric.dim(x);\n'+
21463-        'if(typeof k === "undefined") k = 0;\n'+
21464-        'if(k === s.length-1) return numeric.'+i+'V(x);\n'+
21465-        'var xi;\n'+
21466-        'var n = x.length, i;\n'+
21467-        'for(i=n-1;i!==-1;--i) {\n'+
21468-        '   xi = arguments.callee(x[i]);\n'+
21469-        o[0]+';\n'+
21470-        '}\n'+
21471-        'return accum;\n');
21472-    }
21473-  }
21474-}());
21475-
21476-numeric.truncVV = numeric.pointwise(['x[i]','y[i]'],'ret[i] = round(x[i]/y[i])*y[i];','var round = Math.round;');
21477-numeric.truncVS = numeric.pointwise(['x[i]','y'],'ret[i] = round(x[i]/y)*y;','var round = Math.round;');
21478-numeric.truncSV = numeric.pointwise(['x','y[i]'],'ret[i] = round(x/y[i])*y[i];','var round = Math.round;');
21479-numeric.trunc = function trunc(x,y) {
21480-  if(typeof x === "object") {
21481-    if(typeof y === "object") return numeric.truncVV(x,y);
21482-    return numeric.truncVS(x,y);
21483-  }
21484-  if (typeof y === "object") return numeric.truncSV(x,y);
21485-  return Math.round(x/y)*y;
21486-}
21487-
21488-numeric.inv = function inv(x) {
21489-  var s = numeric.dim(x), abs = Math.abs, m = s[0], n = s[1];
21490-  var A = numeric.clone(x), Ai, Aj;
21491-  var I = numeric.identity(m), Ii, Ij;
21492-  var i,j,k,x;
21493-  for(j=0;j<n;++j) {
21494-    var i0 = -1;
21495-    var v0 = -1;
21496-    for(i=j;i!==m;++i) { k = abs(A[i][j]); if(k>v0) { i0 = i; v0 = k; } }
21497-    Aj = A[i0]; A[i0] = A[j]; A[j] = Aj;
21498-    Ij = I[i0]; I[i0] = I[j]; I[j] = Ij;
21499-    x = Aj[j];
21500-    for(k=j;k!==n;++k)    Aj[k] /= x;
21501-    for(k=n-1;k!==-1;--k) Ij[k] /= x;
21502-    for(i=m-1;i!==-1;--i) {
21503-      if(i!==j) {
21504-        Ai = A[i];
21505-        Ii = I[i];
21506-        x = Ai[j];
21507-        for(k=j+1;k!==n;++k)  Ai[k] -= Aj[k]*x;
21508-        for(k=n-1;k>0;--k) { Ii[k] -= Ij[k]*x; --k; Ii[k] -= Ij[k]*x; }
21509-        if(k===0) Ii[0] -= Ij[0]*x;
21510-      }
21511-    }
21512-  }
21513-  return I;
21514-}
21515-
21516-numeric.det = function det(x) {
21517-  var s = numeric.dim(x);
21518-  if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: det() only works on square matrices'); }
21519-  var n = s[0], ret = 1,i,j,k,A = numeric.clone(x),Aj,Ai,alpha,temp,k1,k2,k3;
21520-  for(j=0;j<n-1;j++) {
21521-    k=j;
21522-    for(i=j+1;i<n;i++) { if(Math.abs(A[i][j]) > Math.abs(A[k][j])) { k = i; } }
21523-    if(k !== j) {
21524-      temp = A[k]; A[k] = A[j]; A[j] = temp;
21525-      ret *= -1;
21526-    }
21527-    Aj = A[j];
21528-    for(i=j+1;i<n;i++) {
21529-      Ai = A[i];
21530-      alpha = Ai[j]/Aj[j];
21531-      for(k=j+1;k<n-1;k+=2) {
21532-        k1 = k+1;
21533-        Ai[k] -= Aj[k]*alpha;
21534-        Ai[k1] -= Aj[k1]*alpha;
21535-      }
21536-      if(k!==n) { Ai[k] -= Aj[k]*alpha; }
21537-    }
21538-    if(Aj[j] === 0) { return 0; }
21539-    ret *= Aj[j];
21540-  }
21541-  return ret*A[j][j];
21542-}
21543-
21544-numeric.transpose = function transpose(x) {
21545-  var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj;
21546-  for(j=0;j<n;j++) ret[j] = Array(m);
21547-  for(i=m-1;i>=1;i-=2) {
21548-    A1 = x[i];
21549-    A0 = x[i-1];
21550-    for(j=n-1;j>=1;--j) {
21551-      Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j];
21552-      --j;
21553-      Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j];
21554-    }
21555-    if(j===0) {
21556-      Bj = ret[0]; Bj[i] = A1[0]; Bj[i-1] = A0[0];
21557-    }
21558-  }
21559-  if(i===0) {
21560-    A0 = x[0];
21561-    for(j=n-1;j>=1;--j) {
21562-      ret[j][0] = A0[j];
21563-      --j;
21564-      ret[j][0] = A0[j];
21565-    }
21566-    if(j===0) { ret[0][0] = A0[0]; }
21567-  }
21568-  return ret;
21569-}
21570-numeric.negtranspose = function negtranspose(x) {
21571-  var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj;
21572-  for(j=0;j<n;j++) ret[j] = Array(m);
21573-  for(i=m-1;i>=1;i-=2) {
21574-    A1 = x[i];
21575-    A0 = x[i-1];
21576-    for(j=n-1;j>=1;--j) {
21577-      Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j];
21578-      --j;
21579-      Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j];
21580-    }
21581-    if(j===0) {
21582-      Bj = ret[0]; Bj[i] = -A1[0]; Bj[i-1] = -A0[0];
21583-    }
21584-  }
21585-  if(i===0) {
21586-    A0 = x[0];
21587-    for(j=n-1;j>=1;--j) {
21588-      ret[j][0] = -A0[j];
21589-      --j;
21590-      ret[j][0] = -A0[j];
21591-    }
21592-    if(j===0) { ret[0][0] = -A0[0]; }
21593-  }
21594-  return ret;
21595-}
21596-
21597-numeric._random = function _random(s,k) {
21598-  var i,n=s[k],ret=Array(n), rnd;
21599-  if(k === s.length-1) {
21600-    rnd = Math.random;
21601-    for(i=n-1;i>=1;i-=2) {
21602-      ret[i] = rnd();
21603-      ret[i-1] = rnd();
21604-    }
21605-    if(i===0) { ret[0] = rnd(); }
21606-    return ret;
21607-  }
21608-  for(i=n-1;i>=0;i--) ret[i] = _random(s,k+1);
21609-  return ret;
21610-}
21611-numeric.random = function random(s) { return numeric._random(s,0); }
21612-
21613-numeric.norm2 = function norm2(x) { return Math.sqrt(numeric.norm2Squared(x)); }
21614-
21615-numeric.linspace = function linspace(a,b,n) {
21616-  if(typeof n === "undefined") n = Math.max(Math.round(b-a)+1,1);
21617-  if(n<2) { return n===1?[a]:[]; }
21618-  var i,ret = Array(n);
21619-  n--;
21620-  for(i=n;i>=0;i--) { ret[i] = (i*b+(n-i)*a)/n; }
21621-  return ret;
21622-}
21623-
21624-numeric.getBlock = function getBlock(x,from,to) {
21625-  var s = numeric.dim(x);
21626-  function foo(x,k) {
21627-    var i,a = from[k], n = to[k]-a, ret = Array(n);
21628-    if(k === s.length-1) {
21629-      for(i=n;i>=0;i--) { ret[i] = x[i+a]; }
21630-      return ret;
21631-    }
21632-    for(i=n;i>=0;i--) { ret[i] = foo(x[i+a],k+1); }
21633-    return ret;
21634-  }
21635-  return foo(x,0);
21636-}
21637-
21638-numeric.setBlock = function setBlock(x,from,to,B) {
21639-  var s = numeric.dim(x);
21640-  function foo(x,y,k) {
21641-    var i,a = from[k], n = to[k]-a;
21642-    if(k === s.length-1) { for(i=n;i>=0;i--) { x[i+a] = y[i]; } }
21643-    for(i=n;i>=0;i--) { foo(x[i+a],y[i],k+1); }
21644-  }
21645-  foo(x,B,0);
21646-  return x;
21647-}
21648-
21649-numeric.getRange = function getRange(A,I,J) {
21650-  var m = I.length, n = J.length;
21651-  var i,j;
21652-  var B = Array(m), Bi, AI;
21653-  for(i=m-1;i!==-1;--i) {
21654-    B[i] = Array(n);
21655-    Bi = B[i];
21656-    AI = A[I[i]];
21657-    for(j=n-1;j!==-1;--j) Bi[j] = AI[J[j]];
21658-  }
21659-  return B;
21660-}
21661-
21662-numeric.blockMatrix = function blockMatrix(X) {
21663-  var s = numeric.dim(X);
21664-  if(s.length<4) return numeric.blockMatrix([X]);
21665-  var m=s[0],n=s[1],M,N,i,j,Xij;
21666-  M = 0; N = 0;
21667-  for(i=0;i<m;++i) M+=X[i][0].length;
21668-  for(j=0;j<n;++j) N+=X[0][j][0].length;
21669-  var Z = Array(M);
21670-  for(i=0;i<M;++i) Z[i] = Array(N);
21671-  var I=0,J,ZI,k,l,Xijk;
21672-  for(i=0;i<m;++i) {
21673-    J=N;
21674-    for(j=n-1;j!==-1;--j) {
21675-      Xij = X[i][j];
21676-      J -= Xij[0].length;
21677-      for(k=Xij.length-1;k!==-1;--k) {
21678-        Xijk = Xij[k];
21679-        ZI = Z[I+k];
21680-        for(l = Xijk.length-1;l!==-1;--l) ZI[J+l] = Xijk[l];
21681-      }
21682-    }
21683-    I += X[i][0].length;
21684-  }
21685-  return Z;
21686-}
21687-
21688-numeric.tensor = function tensor(x,y) {
21689-  if(typeof x === "number" || typeof y === "number") return numeric.mul(x,y);
21690-  var s1 = numeric.dim(x), s2 = numeric.dim(y);
21691-  if(s1.length !== 1 || s2.length !== 1) {
21692-    throw new Error('numeric: tensor product is only defined for vectors');
21693-  }
21694-  var m = s1[0], n = s2[0], A = Array(m), Ai, i,j,xi;
21695-  for(i=m-1;i>=0;i--) {
21696-    Ai = Array(n);
21697-    xi = x[i];
21698-    for(j=n-1;j>=3;--j) {
21699-      Ai[j] = xi * y[j];
21700-      --j;
21701-      Ai[j] = xi * y[j];
21702-      --j;
21703-      Ai[j] = xi * y[j];
21704-      --j;
21705-      Ai[j] = xi * y[j];
21706-    }
21707-    while(j>=0) { Ai[j] = xi * y[j]; --j; }
21708-    A[i] = Ai;
21709-  }
21710-  return A;
21711-}
21712-
21713-// 3. The Tensor type T
21714-numeric.T = function T(x,y) { this.x = x; this.y = y; }
21715-numeric.t = function t(x,y) { return new numeric.T(x,y); }
21716-
21717-numeric.Tbinop = function Tbinop(rr,rc,cr,cc,setup) {
21718-  var io = numeric.indexOf;
21719-  if(typeof setup !== "string") {
21720-    var k;
21721-    setup = '';
21722-    for(k in numeric) {
21723-      if(numeric.hasOwnProperty(k) && (rr.indexOf(k)>=0 || rc.indexOf(k)>=0 || cr.indexOf(k)>=0 || cc.indexOf(k)>=0) && k.length>1) {
21724-        setup += 'var '+k+' = numeric.'+k+';\n';
21725-      }
21726-    }
21727-  }
21728-  return Function(['y'],
21729-    'var x = this;\n'+
21730-    'if(!(y instanceof numeric.T)) { y = new numeric.T(y); }\n'+
21731-    setup+'\n'+
21732-    'if(x.y) {'+
21733-    '  if(y.y) {'+
21734-    '    return new numeric.T('+cc+');\n'+
21735-    '  }\n'+
21736-    '  return new numeric.T('+cr+');\n'+
21737-    '}\n'+
21738-    'if(y.y) {\n'+
21739-    '  return new numeric.T('+rc+');\n'+
21740-    '}\n'+
21741-    'return new numeric.T('+rr+');\n'
21742-  );
21743-}
21744-
21745-numeric.T.prototype.add = numeric.Tbinop(
21746-  'add(x.x,y.x)',
21747-  'add(x.x,y.x),y.y',
21748-  'add(x.x,y.x),x.y',
21749-  'add(x.x,y.x),add(x.y,y.y)');
21750-numeric.T.prototype.sub = numeric.Tbinop(
21751-  'sub(x.x,y.x)',
21752-  'sub(x.x,y.x),neg(y.y)',
21753-  'sub(x.x,y.x),x.y',
21754-  'sub(x.x,y.x),sub(x.y,y.y)');
21755-numeric.T.prototype.mul = numeric.Tbinop(
21756-  'mul(x.x,y.x)',
21757-  'mul(x.x,y.x),mul(x.x,y.y)',
21758-  'mul(x.x,y.x),mul(x.y,y.x)',
21759-  'sub(mul(x.x,y.x),mul(x.y,y.y)),add(mul(x.x,y.y),mul(x.y,y.x))');
21760-
21761-numeric.T.prototype.reciprocal = function reciprocal() {
21762-  var mul = numeric.mul, div = numeric.div;
21763-  if(this.y) {
21764-    var d = numeric.add(mul(this.x,this.x),mul(this.y,this.y));
21765-    return new numeric.T(div(this.x,d),div(numeric.neg(this.y),d));
21766-  }
21767-  return new T(div(1,this.x));
21768-}
21769-numeric.T.prototype.div = function div(y) {
21770-  if(!(y instanceof numeric.T)) y = new numeric.T(y);
21771-  if(y.y) { return this.mul(y.reciprocal()); }
21772-  var div = numeric.div;
21773-  if(this.y) { return new numeric.T(div(this.x,y.x),div(this.y,y.x)); }
21774-  return new numeric.T(div(this.x,y.x));
21775-}
21776-numeric.T.prototype.dot = numeric.Tbinop(
21777-  'dot(x.x,y.x)',
21778-  'dot(x.x,y.x),dot(x.x,y.y)',
21779-  'dot(x.x,y.x),dot(x.y,y.x)',
21780-  'sub(dot(x.x,y.x),dot(x.y,y.y)),add(dot(x.x,y.y),dot(x.y,y.x))'
21781-);
21782-numeric.T.prototype.transpose = function transpose() {
21783-  var t = numeric.transpose, x = this.x, y = this.y;
21784-  if(y) { return new numeric.T(t(x),t(y)); }
21785-  return new numeric.T(t(x));
21786-}
21787-numeric.T.prototype.transjugate = function transjugate() {
21788-  var t = numeric.transpose, x = this.x, y = this.y;
21789-  if(y) { return new numeric.T(t(x),numeric.negtranspose(y)); }
21790-  return new numeric.T(t(x));
21791-}
21792-numeric.Tunop = function Tunop(r,c,s) {
21793-  if(typeof s !== "string") { s = ''; }
21794-  return Function(
21795-    'var x = this;\n'+
21796-    s+'\n'+
21797-    'if(x.y) {'+
21798-    '  '+c+';\n'+
21799-    '}\n'+
21800-    r+';\n'
21801-  );
21802-}
21803-
21804-numeric.T.prototype.exp = numeric.Tunop(
21805-  'return new numeric.T(ex)',
21806-  'return new numeric.T(mul(cos(x.y),ex),mul(sin(x.y),ex))',
21807-  'var ex = numeric.exp(x.x), cos = numeric.cos, sin = numeric.sin, mul = numeric.mul;');
21808-numeric.T.prototype.conj = numeric.Tunop(
21809-  'return new numeric.T(x.x);',
21810-  'return new numeric.T(x.x,numeric.neg(x.y));');
21811-numeric.T.prototype.neg = numeric.Tunop(
21812-  'return new numeric.T(neg(x.x));',
21813-  'return new numeric.T(neg(x.x),neg(x.y));',
21814-  'var neg = numeric.neg;');
21815-numeric.T.prototype.sin = numeric.Tunop(
21816-  'return new numeric.T(numeric.sin(x.x))',
21817-  'return x.exp().sub(x.neg().exp()).div(new numeric.T(0,2));');
21818-numeric.T.prototype.cos = numeric.Tunop(
21819-  'return new numeric.T(numeric.cos(x.x))',
21820-  'return x.exp().add(x.neg().exp()).div(2);');
21821-numeric.T.prototype.abs = numeric.Tunop(
21822-  'return new numeric.T(numeric.abs(x.x));',
21823-  'return new numeric.T(numeric.sqrt(numeric.add(mul(x.x,x.x),mul(x.y,x.y))));',
21824-  'var mul = numeric.mul;');
21825-numeric.T.prototype.log = numeric.Tunop(
21826-  'return new numeric.T(numeric.log(x.x));',
21827-  'var theta = new numeric.T(numeric.atan2(x.y,x.x)), r = x.abs();\n'+
21828-  'return new numeric.T(numeric.log(r.x),theta.x);');
21829-numeric.T.prototype.norm2 = numeric.Tunop(
21830-  'return numeric.norm2(x.x);',
21831-  'var f = numeric.norm2Squared;\n'+
21832-  'return Math.sqrt(f(x.x)+f(x.y));');
21833-numeric.T.prototype.inv = function inv() {
21834-  var A = this;
21835-  if(typeof A.y === "undefined") { return new numeric.T(numeric.inv(A.x)); }
21836-  var n = A.x.length, i, j, k;
21837-  var Rx = numeric.identity(n),Ry = numeric.rep([n,n],0);
21838-  var Ax = numeric.clone(A.x), Ay = numeric.clone(A.y);
21839-  var Aix, Aiy, Ajx, Ajy, Rix, Riy, Rjx, Rjy;
21840-  var i,j,k,d,d1,ax,ay,bx,by,temp;
21841-  for(i=0;i<n;i++) {
21842-    ax = Ax[i][i]; ay = Ay[i][i];
21843-    d = ax*ax+ay*ay;
21844-    k = i;
21845-    for(j=i+1;j<n;j++) {
21846-      ax = Ax[j][i]; ay = Ay[j][i];
21847-      d1 = ax*ax+ay*ay;
21848-      if(d1 > d) { k=j; d = d1; }
21849-    }
21850-    if(k!==i) {
21851-      temp = Ax[i]; Ax[i] = Ax[k]; Ax[k] = temp;
21852-      temp = Ay[i]; Ay[i] = Ay[k]; Ay[k] = temp;
21853-      temp = Rx[i]; Rx[i] = Rx[k]; Rx[k] = temp;
21854-      temp = Ry[i]; Ry[i] = Ry[k]; Ry[k] = temp;
21855-    }
21856-    Aix = Ax[i]; Aiy = Ay[i];
21857-    Rix = Rx[i]; Riy = Ry[i];
21858-    ax = Aix[i]; ay = Aiy[i];
21859-    for(j=i+1;j<n;j++) {
21860-      bx = Aix[j]; by = Aiy[j];
21861-      Aix[j] = (bx*ax+by*ay)/d;
21862-      Aiy[j] = (by*ax-bx*ay)/d;
21863-    }
21864-    for(j=0;j<n;j++) {
21865-      bx = Rix[j]; by = Riy[j];
21866-      Rix[j] = (bx*ax+by*ay)/d;
21867-      Riy[j] = (by*ax-bx*ay)/d;
21868-    }
21869-    for(j=i+1;j<n;j++) {
21870-      Ajx = Ax[j]; Ajy = Ay[j];
21871-      Rjx = Rx[j]; Rjy = Ry[j];
21872-      ax = Ajx[i]; ay = Ajy[i];
21873-      for(k=i+1;k<n;k++) {
21874-        bx = Aix[k]; by = Aiy[k];
21875-        Ajx[k] -= bx*ax-by*ay;
21876-        Ajy[k] -= by*ax+bx*ay;
21877-      }
21878-      for(k=0;k<n;k++) {
21879-        bx = Rix[k]; by = Riy[k];
21880-        Rjx[k] -= bx*ax-by*ay;
21881-        Rjy[k] -= by*ax+bx*ay;
21882-      }
21883-    }
21884-  }
21885-  for(i=n-1;i>0;i--) {
21886-    Rix = Rx[i]; Riy = Ry[i];
21887-    for(j=i-1;j>=0;j--) {
21888-      Rjx = Rx[j]; Rjy = Ry[j];
21889-      ax = Ax[j][i]; ay = Ay[j][i];
21890-      for(k=n-1;k>=0;k--) {
21891-        bx = Rix[k]; by = Riy[k];
21892-        Rjx[k] -= ax*bx - ay*by;
21893-        Rjy[k] -= ax*by + ay*bx;
21894-      }
21895-    }
21896-  }
21897-  return new numeric.T(Rx,Ry);
21898-}
21899-numeric.T.prototype.get = function get(i) {
21900-  var x = this.x, y = this.y, k = 0, ik, n = i.length;
21901-  if(y) {
21902-    while(k<n) {
21903-      ik = i[k];
21904-      x = x[ik];
21905-      y = y[ik];
21906-      k++;
21907-    }
21908-    return new numeric.T(x,y);
21909-  }
21910-  while(k<n) {
21911-    ik = i[k];
21912-    x = x[ik];
21913-    k++;
21914-  }
21915-  return new numeric.T(x);
21916-}
21917-numeric.T.prototype.set = function set(i,v) {
21918-  var x = this.x, y = this.y, k = 0, ik, n = i.length, vx = v.x, vy = v.y;
21919-  if(n===0) {
21920-    if(vy) { this.y = vy; }
21921-    else if(y) { this.y = undefined; }
21922-    this.x = x;
21923-    return this;
21924-  }
21925-  if(vy) {
21926-    if(y) { /* ok */ }
21927-    else {
21928-      y = numeric.rep(numeric.dim(x),0);
21929-      this.y = y;
21930-    }
21931-    while(k<n-1) {
21932-      ik = i[k];
21933-      x = x[ik];
21934-      y = y[ik];
21935-      k++;
21936-    }
21937-    ik = i[k];
21938-    x[ik] = vx;
21939-    y[ik] = vy;
21940-    return this;
21941-  }
21942-  if(y) {
21943-    while(k<n-1) {
21944-      ik = i[k];
21945-      x = x[ik];
21946-      y = y[ik];
21947-      k++;
21948-    }
21949-    ik = i[k];
21950-    x[ik] = vx;
21951-    if(vx instanceof Array) y[ik] = numeric.rep(numeric.dim(vx),0);
21952-    else y[ik] = 0;
21953-    return this;
21954-  }
21955-  while(k<n-1) {
21956-    ik = i[k];
21957-    x = x[ik];
21958-    k++;
21959-  }
21960-  ik = i[k];
21961-  x[ik] = vx;
21962-  return this;
21963-}
21964-numeric.T.prototype.getRows = function getRows(i0,i1) {
21965-  var n = i1-i0+1, j;
21966-  var rx = Array(n), ry, x = this.x, y = this.y;
21967-  for(j=i0;j<=i1;j++) { rx[j-i0] = x[j]; }
21968-  if(y) {
21969-    ry = Array(n);
21970-    for(j=i0;j<=i1;j++) { ry[j-i0] = y[j]; }
21971-    return new numeric.T(rx,ry);
21972-  }
21973-  return new numeric.T(rx);
21974-}
21975-numeric.T.prototype.setRows = function setRows(i0,i1,A) {
21976-  var j;
21977-  var rx = this.x, ry = this.y, x = A.x, y = A.y;
21978-  for(j=i0;j<=i1;j++) { rx[j] = x[j-i0]; }
21979-  if(y) {
21980-    if(!ry) { ry = numeric.rep(numeric.dim(rx),0); this.y = ry; }
21981-    for(j=i0;j<=i1;j++) { ry[j] = y[j-i0]; }
21982-  } else if(ry) {
21983-    for(j=i0;j<=i1;j++) { ry[j] = numeric.rep([x[j-i0].length],0); }
21984-  }
21985-  return this;
21986-}
21987-numeric.T.prototype.getRow = function getRow(k) {
21988-  var x = this.x, y = this.y;
21989-  if(y) { return new numeric.T(x[k],y[k]); }
21990-  return new numeric.T(x[k]);
21991-}
21992-numeric.T.prototype.setRow = function setRow(i,v) {
21993-  var rx = this.x, ry = this.y, x = v.x, y = v.y;
21994-  rx[i] = x;
21995-  if(y) {
21996-    if(!ry) { ry = numeric.rep(numeric.dim(rx),0); this.y = ry; }
21997-    ry[i] = y;
21998-  } else if(ry) {
21999-    ry = numeric.rep([x.length],0);
22000-  }
22001-  return this;
22002-}
22003-
22004-numeric.T.prototype.getBlock = function getBlock(from,to) {
22005-  var x = this.x, y = this.y, b = numeric.getBlock;
22006-  if(y) { return new numeric.T(b(x,from,to),b(y,from,to)); }
22007-  return new numeric.T(b(x,from,to));
22008-}
22009-numeric.T.prototype.setBlock = function setBlock(from,to,A) {
22010-  if(!(A instanceof numeric.T)) A = new numeric.T(A);
22011-  var x = this.x, y = this.y, b = numeric.setBlock, Ax = A.x, Ay = A.y;
22012-  if(Ay) {
22013-    if(!y) { this.y = numeric.rep(numeric.dim(this),0); y = this.y; }
22014-    b(x,from,to,Ax);
22015-    b(y,from,to,Ay);
22016-    return this;
22017-  }
22018-  b(x,from,to,Ax);
22019-  if(y) b(y,from,to,numeric.rep(numeric.dim(Ax),0));
22020-}
22021-numeric.T.rep = function rep(s,v) {
22022-  var T = numeric.T;
22023-  if(!(v instanceof T)) v = new T(v);
22024-  var x = v.x, y = v.y, r = numeric.rep;
22025-  if(y) return new T(r(s,x),r(s,y));
22026-  return new T(r(s,x));
22027-}
22028-numeric.T.diag = function diag(d) {
22029-  if(!(d instanceof numeric.T)) d = new numeric.T(d);
22030-  var x = d.x, y = d.y, diag = numeric.diag;
22031-  if(y) return new numeric.T(diag(x),diag(y));
22032-  return new numeric.T(diag(x));
22033-}
22034-numeric.T.eig = function eig() {
22035-  if(this.y) { throw new Error('eig: not implemented for complex matrices.'); }
22036-  return numeric.eig(this.x);
22037-}
22038-numeric.T.identity = function identity(n) { return new numeric.T(numeric.identity(n)); }
22039-numeric.T.prototype.getDiag = function getDiag() {
22040-  var n = numeric;
22041-  var x = this.x, y = this.y;
22042-  if(y) { return new n.T(n.getDiag(x),n.getDiag(y)); }
22043-  return new n.T(n.getDiag(x));
22044-}
22045-
22046-// 4. Eigenvalues of real matrices
22047-
22048-numeric.house = function house(x) {
22049-  var v = numeric.clone(x);
22050-  var s = x[0] >= 0 ? 1 : -1;
22051-  var alpha = s*numeric.norm2(x);
22052-  v[0] += alpha;
22053-  var foo = numeric.norm2(v);
22054-  if(foo === 0) { /* this should not happen */ throw new Error('eig: internal error'); }
22055-  return numeric.div(v,foo);
22056-}
22057-
22058-numeric.toUpperHessenberg = function toUpperHessenberg(me) {
22059-  var s = numeric.dim(me);
22060-  if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: toUpperHessenberg() only works on square matrices'); }
22061-  var m = s[0], i,j,k,x,v,A = numeric.clone(me),B,C,Ai,Ci,Q = numeric.identity(m),Qi;
22062-  for(j=0;j<m-2;j++) {
22063-    x = Array(m-j-1);
22064-    for(i=j+1;i<m;i++) { x[i-j-1] = A[i][j]; }
22065-    if(numeric.norm2(x)>0) {
22066-      v = numeric.house(x);
22067-      B = numeric.getBlock(A,[j+1,j],[m-1,m-1]);
22068-      C = numeric.tensor(v,numeric.dot(v,B));
22069-      for(i=j+1;i<m;i++) { Ai = A[i]; Ci = C[i-j-1]; for(k=j;k<m;k++) Ai[k] -= 2*Ci[k-j]; }
22070-      B = numeric.getBlock(A,[0,j+1],[m-1,m-1]);
22071-      C = numeric.tensor(numeric.dot(B,v),v);
22072-      for(i=0;i<m;i++) { Ai = A[i]; Ci = C[i]; for(k=j+1;k<m;k++) Ai[k] -= 2*Ci[k-j-1]; }
22073-      B = Array(m-j-1);
22074-      for(i=j+1;i<m;i++) B[i-j-1] = Q[i];
22075-      C = numeric.tensor(v,numeric.dot(v,B));
22076-      for(i=j+1;i<m;i++) { Qi = Q[i]; Ci = C[i-j-1]; for(k=0;k<m;k++) Qi[k] -= 2*Ci[k]; }
22077-    }
22078-  }
22079-  return {H:A, Q:Q};
22080-}
22081-
22082-numeric.epsilon = 2.220446049250313e-16;
22083-
22084-numeric.QRFrancis = function(H,maxiter) {
22085-  if(typeof maxiter === "undefined") { maxiter = 10000; }
22086-  H = numeric.clone(H);
22087-  var H0 = numeric.clone(H);
22088-  var s = numeric.dim(H),m=s[0],x,v,a,b,c,d,det,tr, Hloc, Q = numeric.identity(m), Qi, Hi, B, C, Ci,i,j,k,iter;
22089-  if(m<3) { return {Q:Q, B:[ [0,m-1] ]}; }
22090-  var epsilon = numeric.epsilon;
22091-  for(iter=0;iter<maxiter;iter++) {
22092-    for(j=0;j<m-1;j++) {
22093-      if(Math.abs(H[j+1][j]) < epsilon*(Math.abs(H[j][j])+Math.abs(H[j+1][j+1]))) {
22094-        var QH1 = numeric.QRFrancis(numeric.getBlock(H,[0,0],[j,j]),maxiter);
22095-        var QH2 = numeric.QRFrancis(numeric.getBlock(H,[j+1,j+1],[m-1,m-1]),maxiter);
22096-        B = Array(j+1);
22097-        for(i=0;i<=j;i++) { B[i] = Q[i]; }
22098-        C = numeric.dot(QH1.Q,B);
22099-        for(i=0;i<=j;i++) { Q[i] = C[i]; }
22100-        B = Array(m-j-1);
22101-        for(i=j+1;i<m;i++) { B[i-j-1] = Q[i]; }
22102-        C = numeric.dot(QH2.Q,B);
22103-        for(i=j+1;i<m;i++) { Q[i] = C[i-j-1]; }
22104-        return {Q:Q,B:QH1.B.concat(numeric.add(QH2.B,j+1))};
22105-      }
22106-    }
22107-    a = H[m-2][m-2]; b = H[m-2][m-1];
22108-    c = H[m-1][m-2]; d = H[m-1][m-1];
22109-    tr = a+d;
22110-    det = (a*d-b*c);
22111-    Hloc = numeric.getBlock(H, [0,0], [2,2]);
22112-    if(tr*tr>=4*det) {
22113-      var s1,s2;
22114-      s1 = 0.5*(tr+Math.sqrt(tr*tr-4*det));
22115-      s2 = 0.5*(tr-Math.sqrt(tr*tr-4*det));
22116-      Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc),
22117-        numeric.mul(Hloc,s1+s2)),
22118-        numeric.diag(numeric.rep([3],s1*s2)));
22119-    } else {
22120-      Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc),
22121-        numeric.mul(Hloc,tr)),
22122-        numeric.diag(numeric.rep([3],det)));
22123-    }
22124-    x = [Hloc[0][0],Hloc[1][0],Hloc[2][0]];
22125-    v = numeric.house(x);
22126-    B = [H[0],H[1],H[2]];
22127-    C = numeric.tensor(v,numeric.dot(v,B));
22128-    for(i=0;i<3;i++) { Hi = H[i]; Ci = C[i]; for(k=0;k<m;k++) Hi[k] -= 2*Ci[k]; }
22129-    B = numeric.getBlock(H, [0,0],[m-1,2]);
22130-    C = numeric.tensor(numeric.dot(B,v),v);
22131-    for(i=0;i<m;i++) { Hi = H[i]; Ci = C[i]; for(k=0;k<3;k++) Hi[k] -= 2*Ci[k]; }
22132-    B = [Q[0],Q[1],Q[2]];
22133-    C = numeric.tensor(v,numeric.dot(v,B));
22134-    for(i=0;i<3;i++) { Qi = Q[i]; Ci = C[i]; for(k=0;k<m;k++) Qi[k] -= 2*Ci[k]; }
22135-    var J;
22136-    for(j=0;j<m-2;j++) {
22137-      for(k=j;k<=j+1;k++) {
22138-        if(Math.abs(H[k+1][k]) < epsilon*(Math.abs(H[k][k])+Math.abs(H[k+1][k+1]))) {
22139-          var QH1 = numeric.QRFrancis(numeric.getBlock(H,[0,0],[k,k]),maxiter);
22140-          var QH2 = numeric.QRFrancis(numeric.getBlock(H,[k+1,k+1],[m-1,m-1]),maxiter);
22141-          B = Array(k+1);
22142-          for(i=0;i<=k;i++) { B[i] = Q[i]; }
22143-          C = numeric.dot(QH1.Q,B);
22144-          for(i=0;i<=k;i++) { Q[i] = C[i]; }
22145-          B = Array(m-k-1);
22146-          for(i=k+1;i<m;i++) { B[i-k-1] = Q[i]; }
22147-          C = numeric.dot(QH2.Q,B);
22148-          for(i=k+1;i<m;i++) { Q[i] = C[i-k-1]; }
22149-          return {Q:Q,B:QH1.B.concat(numeric.add(QH2.B,k+1))};
22150-        }
22151-      }
22152-      J = Math.min(m-1,j+3);
22153-      x = Array(J-j);
22154-      for(i=j+1;i<=J;i++) { x[i-j-1] = H[i][j]; }
22155-      v = numeric.house(x);
22156-      B = numeric.getBlock(H, [j+1,j],[J,m-1]);
22157-      C = numeric.tensor(v,numeric.dot(v,B));
22158-      for(i=j+1;i<=J;i++) { Hi = H[i]; Ci = C[i-j-1]; for(k=j;k<m;k++) Hi[k] -= 2*Ci[k-j]; }
22159-      B = numeric.getBlock(H, [0,j+1],[m-1,J]);
22160-      C = numeric.tensor(numeric.dot(B,v),v);
22161-      for(i=0;i<m;i++) { Hi = H[i]; Ci = C[i]; for(k=j+1;k<=J;k++) Hi[k] -= 2*Ci[k-j-1]; }
22162-      B = Array(J-j);
22163-      for(i=j+1;i<=J;i++) B[i-j-1] = Q[i];
22164-      C = numeric.tensor(v,numeric.dot(v,B));
22165-      for(i=j+1;i<=J;i++) { Qi = Q[i]; Ci = C[i-j-1]; for(k=0;k<m;k++) Qi[k] -= 2*Ci[k]; }
22166-    }
22167-  }
22168-  throw new Error('numeric: eigenvalue iteration does not converge -- increase maxiter?');
22169-}
22170-
22171-numeric.eig = function eig(A,maxiter) {
22172-  var QH = numeric.toUpperHessenberg(A);
22173-  var QB = numeric.QRFrancis(QH.H,maxiter);
22174-  var T = numeric.T;
22175-  var n = A.length,i,k,flag = false,B = QB.B,H = numeric.dot(QB.Q,numeric.dot(QH.H,numeric.transpose(QB.Q)));
22176-  var Q = new T(numeric.dot(QB.Q,QH.Q)),Q0;
22177-  var m = B.length,j;
22178-  var a,b,c,d,p1,p2,disc,x,y,p,q,n1,n2;
22179-  var sqrt = Math.sqrt;
22180-  for(k=0;k<m;k++) {
22181-    i = B[k][0];
22182-    if(i === B[k][1]) {
22183-      // nothing
22184-    } else {
22185-      j = i+1;
22186-      a = H[i][i];
22187-      b = H[i][j];
22188-      c = H[j][i];
22189-      d = H[j][j];
22190-      if(b === 0 && c === 0) continue;
22191-      p1 = -a-d;
22192-      p2 = a*d-b*c;
22193-      disc = p1*p1-4*p2;
22194-      if(disc>=0) {
22195-        if(p1<0) x = -0.5*(p1-sqrt(disc));
22196-        else     x = -0.5*(p1+sqrt(disc));
22197-        n1 = (a-x)*(a-x)+b*b;
22198-        n2 = c*c+(d-x)*(d-x);
22199-        if(n1>n2) {
22200-          n1 = sqrt(n1);
22201-          p = (a-x)/n1;
22202-          q = b/n1;
22203-        } else {
22204-          n2 = sqrt(n2);
22205-          p = c/n2;
22206-          q = (d-x)/n2;
22207-        }
22208-        Q0 = new T([[q,-p],[p,q]]);
22209-        Q.setRows(i,j,Q0.dot(Q.getRows(i,j)));
22210-      } else {
22211-        x = -0.5*p1;
22212-        y = 0.5*sqrt(-disc);
22213-        n1 = (a-x)*(a-x)+b*b;
22214-        n2 = c*c+(d-x)*(d-x);
22215-        if(n1>n2) {
22216-          n1 = sqrt(n1+y*y);
22217-          p = (a-x)/n1;
22218-          q = b/n1;
22219-          x = 0;
22220-          y /= n1;
22221-        } else {
22222-          n2 = sqrt(n2+y*y);
22223-          p = c/n2;
22224-          q = (d-x)/n2;
22225-          x = y/n2;
22226-          y = 0;
22227-        }
22228-        Q0 = new T([[q,-p],[p,q]],[[x,y],[y,-x]]);
22229-        Q.setRows(i,j,Q0.dot(Q.getRows(i,j)));
22230-      }
22231-    }
22232-  }
22233-  var R = Q.dot(A).dot(Q.transjugate()), n = A.length, E = numeric.T.identity(n);
22234-  for(j=0;j<n;j++) {
22235-    if(j>0) {
22236-      for(k=j-1;k>=0;k--) {
22237-        var Rk = R.get([k,k]), Rj = R.get([j,j]);
22238-        if(numeric.neq(Rk.x,Rj.x) || numeric.neq(Rk.y,Rj.y)) {
22239-          x = R.getRow(k).getBlock([k],[j-1]);
22240-          y = E.getRow(j).getBlock([k],[j-1]);
22241-          E.set([j,k],(R.get([k,j]).neg().sub(x.dot(y))).div(Rk.sub(Rj)));
22242-        } else {
22243-          E.setRow(j,E.getRow(k));
22244-          continue;
22245-        }
22246-      }
22247-    }
22248-  }
22249-  for(j=0;j<n;j++) {
22250-    x = E.getRow(j);
22251-    E.setRow(j,x.div(x.norm2()));
22252-  }
22253-  E = E.transpose();
22254-  E = Q.transjugate().dot(E);
22255-  return { lambda:R.getDiag(), E:E };
22256-};
22257-
22258-// 5. Compressed Column Storage matrices
22259-numeric.ccsSparse = function ccsSparse(A) {
22260-  var m = A.length,n,foo, i,j, counts = [];
22261-  for(i=m-1;i!==-1;--i) {
22262-    foo = A[i];
22263-    for(j in foo) {
22264-      j = parseInt(j);
22265-      while(j>=counts.length) counts[counts.length] = 0;
22266-      if(foo[j]!==0) counts[j]++;
22267-    }
22268-  }
22269-  var n = counts.length;
22270-  var Ai = Array(n+1);
22271-  Ai[0] = 0;
22272-  for(i=0;i<n;++i) Ai[i+1] = Ai[i] + counts[i];
22273-  var Aj = Array(Ai[n]), Av = Array(Ai[n]);
22274-  for(i=m-1;i!==-1;--i) {
22275-    foo = A[i];
22276-    for(j in foo) {
22277-      if(foo[j]!==0) {
22278-        counts[j]--;
22279-        Aj[Ai[j]+counts[j]] = i;
22280-        Av[Ai[j]+counts[j]] = foo[j];
22281-      }
22282-    }
22283-  }
22284-  return [Ai,Aj,Av];
22285-}
22286-numeric.ccsFull = function ccsFull(A) {
22287-  var Ai = A[0], Aj = A[1], Av = A[2], s = numeric.ccsDim(A), m = s[0], n = s[1], i,j,j0,j1,k;
22288-  var B = numeric.rep([m,n],0);
22289-  for(i=0;i<n;i++) {
22290-    j0 = Ai[i];
22291-    j1 = Ai[i+1];
22292-    for(j=j0;j<j1;++j) { B[Aj[j]][i] = Av[j]; }
22293-  }
22294-  return B;
22295-}
22296-numeric.ccsTSolve = function ccsTSolve(A,b,x,bj,xj) {
22297-  var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1, max = Math.max,n=0;
22298-  if(typeof bj === "undefined") x = numeric.rep([m],0);
22299-  if(typeof bj === "undefined") bj = numeric.linspace(0,x.length-1);
22300-  if(typeof xj === "undefined") xj = [];
22301-  function dfs(j) {
22302-    var k;
22303-    if(x[j] !== 0) return;
22304-    x[j] = 1;
22305-    for(k=Ai[j];k<Ai[j+1];++k) dfs(Aj[k]);
22306-    xj[n] = j;
22307-    ++n;
22308-  }
22309-  var i,j,j0,j1,k,l,l0,l1,a;
22310-  for(i=bj.length-1;i!==-1;--i) { dfs(bj[i]); }
22311-  xj.length = n;
22312-  for(i=xj.length-1;i!==-1;--i) { x[xj[i]] = 0; }
22313-  for(i=bj.length-1;i!==-1;--i) { j = bj[i]; x[j] = b[j]; }
22314-  for(i=xj.length-1;i!==-1;--i) {
22315-    j = xj[i];
22316-    j0 = Ai[j];
22317-    j1 = max(Ai[j+1],j0);
22318-    for(k=j0;k!==j1;++k) { if(Aj[k] === j) { x[j] /= Av[k]; break; } }
22319-    a = x[j];
22320-    for(k=j0;k!==j1;++k) {
22321-      l = Aj[k];
22322-      if(l !== j) x[l] -= a*Av[k];
22323-    }
22324-  }
22325-  return x;
22326-}
22327-numeric.ccsDFS = function ccsDFS(n) {
22328-  this.k = Array(n);
22329-  this.k1 = Array(n);
22330-  this.j = Array(n);
22331-}
22332-numeric.ccsDFS.prototype.dfs = function dfs(J,Ai,Aj,x,xj,Pinv) {
22333-  var m = 0,foo,n=xj.length;
22334-  var k = this.k, k1 = this.k1, j = this.j,km,k11;
22335-  if(x[J]!==0) return;
22336-  x[J] = 1;
22337-  j[0] = J;
22338-  k[0] = km = Ai[J];
22339-  k1[0] = k11 = Ai[J+1];
22340-  while(1) {
22341-    if(km >= k11) {
22342-      xj[n] = j[m];
22343-      if(m===0) return;
22344-      ++n;
22345-      --m;
22346-      km = k[m];
22347-      k11 = k1[m];
22348-    } else {
22349-      foo = Pinv[Aj[km]];
22350-      if(x[foo] === 0) {
22351-        x[foo] = 1;
22352-        k[m] = km;
22353-        ++m;
22354-        j[m] = foo;
22355-        km = Ai[foo];
22356-        k1[m] = k11 = Ai[foo+1];
22357-      } else ++km;
22358-    }
22359-  }
22360-}
22361-numeric.ccsLPSolve = function ccsLPSolve(A,B,x,xj,I,Pinv,dfs) {
22362-  var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1, n=0;
22363-  var Bi = B[0], Bj = B[1], Bv = B[2];
22364-
22365-  var i,i0,i1,j,J,j0,j1,k,l,l0,l1,a;
22366-  i0 = Bi[I];
22367-  i1 = Bi[I+1];
22368-  xj.length = 0;
22369-  for(i=i0;i<i1;++i) { dfs.dfs(Pinv[Bj[i]],Ai,Aj,x,xj,Pinv); }
22370-  for(i=xj.length-1;i!==-1;--i) { x[xj[i]] = 0; }
22371-  for(i=i0;i!==i1;++i) { j = Pinv[Bj[i]]; x[j] = Bv[i]; }
22372-  for(i=xj.length-1;i!==-1;--i) {
22373-    j = xj[i];
22374-    j0 = Ai[j];
22375-    j1 = Ai[j+1];
22376-    for(k=j0;k<j1;++k) { if(Pinv[Aj[k]] === j) { x[j] /= Av[k]; break; } }
22377-    a = x[j];
22378-    for(k=j0;k<j1;++k) {
22379-      l = Pinv[Aj[k]];
22380-      if(l !== j) x[l] -= a*Av[k];
22381-    }
22382-  }
22383-  return x;
22384-}
22385-numeric.ccsLUP1 = function ccsLUP1(A,threshold) {
22386-  var m = A[0].length-1;
22387-  var L = [numeric.rep([m+1],0),[],[]], U = [numeric.rep([m+1], 0),[],[]];
22388-  var Li = L[0], Lj = L[1], Lv = L[2], Ui = U[0], Uj = U[1], Uv = U[2];
22389-  var x = numeric.rep([m],0), xj = numeric.rep([m],0);
22390-  var i,j,k,j0,j1,a,e,c,d,K;
22391-  var sol = numeric.ccsLPSolve, max = Math.max, abs = Math.abs;
22392-  var P = numeric.linspace(0,m-1),Pinv = numeric.linspace(0,m-1);
22393-  var dfs = new numeric.ccsDFS(m);
22394-  if(typeof threshold === "undefined") { threshold = 1; }
22395-  for(i=0;i<m;++i) {
22396-    sol(L,A,x,xj,i,Pinv,dfs);
22397-    a = -1;
22398-    e = -1;
22399-    for(j=xj.length-1;j!==-1;--j) {
22400-      k = xj[j];
22401-      if(k <= i) continue;
22402-      c = abs(x[k]);
22403-      if(c > a) { e = k; a = c; }
22404-    }
22405-    if(abs(x[i])<threshold*a) {
22406-      j = P[i];
22407-      a = P[e];
22408-      P[i] = a; Pinv[a] = i;
22409-      P[e] = j; Pinv[j] = e;
22410-      a = x[i]; x[i] = x[e]; x[e] = a;
22411-    }
22412-    a = Li[i];
22413-    e = Ui[i];
22414-    d = x[i];
22415-    Lj[a] = P[i];
22416-    Lv[a] = 1;
22417-    ++a;
22418-    for(j=xj.length-1;j!==-1;--j) {
22419-      k = xj[j];
22420-      c = x[k];
22421-      xj[j] = 0;
22422-      x[k] = 0;
22423-      if(k<=i) { Uj[e] = k; Uv[e] = c;   ++e; }
22424-      else     { Lj[a] = P[k]; Lv[a] = c/d; ++a; }
22425-    }
22426-    Li[i+1] = a;
22427-    Ui[i+1] = e;
22428-  }
22429-  for(j=Lj.length-1;j!==-1;--j) { Lj[j] = Pinv[Lj[j]]; }
22430-  return {L:L, U:U, P:P, Pinv:Pinv};
22431-}
22432-numeric.ccsDFS0 = function ccsDFS0(n) {
22433-  this.k = Array(n);
22434-  this.k1 = Array(n);
22435-  this.j = Array(n);
22436-}
22437-numeric.ccsDFS0.prototype.dfs = function dfs(J,Ai,Aj,x,xj,Pinv,P) {
22438-  var m = 0,foo,n=xj.length;
22439-  var k = this.k, k1 = this.k1, j = this.j,km,k11;
22440-  if(x[J]!==0) return;
22441-  x[J] = 1;
22442-  j[0] = J;
22443-  k[0] = km = Ai[Pinv[J]];
22444-  k1[0] = k11 = Ai[Pinv[J]+1];
22445-  while(1) {
22446-    if(isNaN(km)) throw new Error("Ow!");
22447-    if(km >= k11) {
22448-      xj[n] = Pinv[j[m]];
22449-      if(m===0) return;
22450-      ++n;
22451-      --m;
22452-      km = k[m];
22453-      k11 = k1[m];
22454-    } else {
22455-      foo = Aj[km];
22456-      if(x[foo] === 0) {
22457-        x[foo] = 1;
22458-        k[m] = km;
22459-        ++m;
22460-        j[m] = foo;
22461-        foo = Pinv[foo];
22462-        km = Ai[foo];
22463-        k1[m] = k11 = Ai[foo+1];
22464-      } else ++km;
22465-    }
22466-  }
22467-}
22468-numeric.ccsLPSolve0 = function ccsLPSolve0(A,B,y,xj,I,Pinv,P,dfs) {
22469-  var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1, n=0;
22470-  var Bi = B[0], Bj = B[1], Bv = B[2];
22471-
22472-  var i,i0,i1,j,J,j0,j1,k,l,l0,l1,a;
22473-  i0 = Bi[I];
22474-  i1 = Bi[I+1];
22475-  xj.length = 0;
22476-  for(i=i0;i<i1;++i) { dfs.dfs(Bj[i],Ai,Aj,y,xj,Pinv,P); }
22477-  for(i=xj.length-1;i!==-1;--i) { j = xj[i]; y[P[j]] = 0; }
22478-  for(i=i0;i!==i1;++i) { j = Bj[i]; y[j] = Bv[i]; }
22479-  for(i=xj.length-1;i!==-1;--i) {
22480-    j = xj[i];
22481-    l = P[j];
22482-    j0 = Ai[j];
22483-    j1 = Ai[j+1];
22484-    for(k=j0;k<j1;++k) { if(Aj[k] === l) { y[l] /= Av[k]; break; } }
22485-    a = y[l];
22486-    for(k=j0;k<j1;++k) y[Aj[k]] -= a*Av[k];
22487-    y[l] = a;
22488-  }
22489-}
22490-numeric.ccsLUP0 = function ccsLUP0(A,threshold) {
22491-  var m = A[0].length-1;
22492-  var L = [numeric.rep([m+1],0),[],[]], U = [numeric.rep([m+1], 0),[],[]];
22493-  var Li = L[0], Lj = L[1], Lv = L[2], Ui = U[0], Uj = U[1], Uv = U[2];
22494-  var y = numeric.rep([m],0), xj = numeric.rep([m],0);
22495-  var i,j,k,j0,j1,a,e,c,d,K;
22496-  var sol = numeric.ccsLPSolve0, max = Math.max, abs = Math.abs;
22497-  var P = numeric.linspace(0,m-1),Pinv = numeric.linspace(0,m-1);
22498-  var dfs = new numeric.ccsDFS0(m);
22499-  if(typeof threshold === "undefined") { threshold = 1; }
22500-  for(i=0;i<m;++i) {
22501-    sol(L,A,y,xj,i,Pinv,P,dfs);
22502-    a = -1;
22503-    e = -1;
22504-    for(j=xj.length-1;j!==-1;--j) {
22505-      k = xj[j];
22506-      if(k <= i) continue;
22507-      c = abs(y[P[k]]);
22508-      if(c > a) { e = k; a = c; }
22509-    }
22510-    if(abs(y[P[i]])<threshold*a) {
22511-      j = P[i];
22512-      a = P[e];
22513-      P[i] = a; Pinv[a] = i;
22514-      P[e] = j; Pinv[j] = e;
22515-    }
22516-    a = Li[i];
22517-    e = Ui[i];
22518-    d = y[P[i]];
22519-    Lj[a] = P[i];
22520-    Lv[a] = 1;
22521-    ++a;
22522-    for(j=xj.length-1;j!==-1;--j) {
22523-      k = xj[j];
22524-      c = y[P[k]];
22525-      xj[j] = 0;
22526-      y[P[k]] = 0;
22527-      if(k<=i) { Uj[e] = k; Uv[e] = c;   ++e; }
22528-      else     { Lj[a] = P[k]; Lv[a] = c/d; ++a; }
22529-    }
22530-    Li[i+1] = a;
22531-    Ui[i+1] = e;
22532-  }
22533-  for(j=Lj.length-1;j!==-1;--j) { Lj[j] = Pinv[Lj[j]]; }
22534-  return {L:L, U:U, P:P, Pinv:Pinv};
22535-}
22536-numeric.ccsLUP = numeric.ccsLUP0;
22537-
22538-numeric.ccsDim = function ccsDim(A) { return [numeric.sup(A[1])+1,A[0].length-1]; }
22539-numeric.ccsGetBlock = function ccsGetBlock(A,i,j) {
22540-  var s = numeric.ccsDim(A),m=s[0],n=s[1];
22541-  if(typeof i === "undefined") { i = numeric.linspace(0,m-1); }
22542-  else if(typeof i === "number") { i = [i]; }
22543-  if(typeof j === "undefined") { j = numeric.linspace(0,n-1); }
22544-  else if(typeof j === "number") { j = [j]; }
22545-  var p,p0,p1,P = i.length,q,Q = j.length,r,jq,ip;
22546-  var Bi = numeric.rep([n],0), Bj=[], Bv=[], B = [Bi,Bj,Bv];
22547-  var Ai = A[0], Aj = A[1], Av = A[2];
22548-  var x = numeric.rep([m],0),count=0,flags = numeric.rep([m],0);
22549-  for(q=0;q<Q;++q) {
22550-    jq = j[q];
22551-    var q0 = Ai[jq];
22552-    var q1 = Ai[jq+1];
22553-    for(p=q0;p<q1;++p) {
22554-      r = Aj[p];
22555-      flags[r] = 1;
22556-      x[r] = Av[p];
22557-    }
22558-    for(p=0;p<P;++p) {
22559-      ip = i[p];
22560-      if(flags[ip]) {
22561-        Bj[count] = p;
22562-        Bv[count] = x[i[p]];
22563-        ++count;
22564-      }
22565-    }
22566-    for(p=q0;p<q1;++p) {
22567-      r = Aj[p];
22568-      flags[r] = 0;
22569-    }
22570-    Bi[q+1] = count;
22571-  }
22572-  return B;
22573-}
22574-
22575-numeric.ccsDot = function ccsDot(A,B) {
22576-  var Ai = A[0], Aj = A[1], Av = A[2];
22577-  var Bi = B[0], Bj = B[1], Bv = B[2];
22578-  var sA = numeric.ccsDim(A), sB = numeric.ccsDim(B);
22579-  var m = sA[0], n = sA[1], o = sB[1];
22580-  var x = numeric.rep([m],0), flags = numeric.rep([m],0), xj = Array(m);
22581-  var Ci = numeric.rep([o],0), Cj = [], Cv = [], C = [Ci,Cj,Cv];
22582-  var i,j,k,j0,j1,i0,i1,l,p,a,b;
22583-  for(k=0;k!==o;++k) {
22584-    j0 = Bi[k];
22585-    j1 = Bi[k+1];
22586-    p = 0;
22587-    for(j=j0;j<j1;++j) {
22588-      a = Bj[j];
22589-      b = Bv[j];
22590-      i0 = Ai[a];
22591-      i1 = Ai[a+1];
22592-      for(i=i0;i<i1;++i) {
22593-        l = Aj[i];
22594-        if(flags[l]===0) {
22595-          xj[p] = l;
22596-          flags[l] = 1;
22597-          p = p+1;
22598-        }
22599-        x[l] = x[l] + Av[i]*b;
22600-      }
22601-    }
22602-    j0 = Ci[k];
22603-    j1 = j0+p;
22604-    Ci[k+1] = j1;
22605-    for(j=p-1;j!==-1;--j) {
22606-      b = j0+j;
22607-      i = xj[j];
22608-      Cj[b] = i;
22609-      Cv[b] = x[i];
22610-      flags[i] = 0;
22611-      x[i] = 0;
22612-    }
22613-    Ci[k+1] = Ci[k]+p;
22614-  }
22615-  return C;
22616-}
22617-
22618-numeric.ccsLUPSolve = function ccsLUPSolve(LUP,B) {
22619-  var L = LUP.L, U = LUP.U, P = LUP.P;
22620-  var Bi = B[0];
22621-  var flag = false;
22622-  if(typeof Bi !== "object") { B = [[0,B.length],numeric.linspace(0,B.length-1),B]; Bi = B[0]; flag = true; }
22623-  var Bj = B[1], Bv = B[2];
22624-  var n = L[0].length-1, m = Bi.length-1;
22625-  var x = numeric.rep([n],0), xj = Array(n);
22626-  var b = numeric.rep([n],0), bj = Array(n);
22627-  var Xi = numeric.rep([m+1],0), Xj = [], Xv = [];
22628-  var sol = numeric.ccsTSolve;
22629-  var i,j,j0,j1,k,J,N=0;
22630-  for(i=0;i<m;++i) {
22631-    k = 0;
22632-    j0 = Bi[i];
22633-    j1 = Bi[i+1];
22634-    for(j=j0;j<j1;++j) {
22635-      J = LUP.Pinv[Bj[j]];
22636-      bj[k] = J;
22637-      b[J] = Bv[j];
22638-      ++k;
22639-    }
22640-    bj.length = k;
22641-    sol(L,b,x,bj,xj);
22642-    for(j=bj.length-1;j!==-1;--j) b[bj[j]] = 0;
22643-    sol(U,x,b,xj,bj);
22644-    if(flag) return b;
22645-    for(j=xj.length-1;j!==-1;--j) x[xj[j]] = 0;
22646-    for(j=bj.length-1;j!==-1;--j) {
22647-      J = bj[j];
22648-      Xj[N] = J;
22649-      Xv[N] = b[J];
22650-      b[J] = 0;
22651-      ++N;
22652-    }
22653-    Xi[i+1] = N;
22654-  }
22655-  return [Xi,Xj,Xv];
22656-}
22657-
22658-numeric.ccsbinop = function ccsbinop(body,setup) {
22659-  if(typeof setup === "undefined") setup='';
22660-  return Function('X','Y',
22661-    'var Xi = X[0], Xj = X[1], Xv = X[2];\n'+
22662-    'var Yi = Y[0], Yj = Y[1], Yv = Y[2];\n'+
22663-    'var n = Xi.length-1,m = Math.max(numeric.sup(Xj),numeric.sup(Yj))+1;\n'+
22664-    'var Zi = numeric.rep([n+1],0), Zj = [], Zv = [];\n'+
22665-    'var x = numeric.rep([m],0),y = numeric.rep([m],0);\n'+
22666-    'var xk,yk,zk;\n'+
22667-    'var i,j,j0,j1,k,p=0;\n'+
22668-    setup+
22669-    'for(i=0;i<n;++i) {\n'+
22670-    '  j0 = Xi[i]; j1 = Xi[i+1];\n'+
22671-    '  for(j=j0;j!==j1;++j) {\n'+
22672-    '    k = Xj[j];\n'+
22673-    '    x[k] = 1;\n'+
22674-    '    Zj[p] = k;\n'+
22675-    '    ++p;\n'+
22676-    '  }\n'+
22677-    '  j0 = Yi[i]; j1 = Yi[i+1];\n'+
22678-    '  for(j=j0;j!==j1;++j) {\n'+
22679-    '    k = Yj[j];\n'+
22680-    '    y[k] = Yv[j];\n'+
22681-    '    if(x[k] === 0) {\n'+
22682-    '      Zj[p] = k;\n'+
22683-    '      ++p;\n'+
22684-    '    }\n'+
22685-    '  }\n'+
22686-    '  Zi[i+1] = p;\n'+
22687-    '  j0 = Xi[i]; j1 = Xi[i+1];\n'+
22688-    '  for(j=j0;j!==j1;++j) x[Xj[j]] = Xv[j];\n'+
22689-    '  j0 = Zi[i]; j1 = Zi[i+1];\n'+
22690-    '  for(j=j0;j!==j1;++j) {\n'+
22691-    '    k = Zj[j];\n'+
22692-    '    xk = x[k];\n'+
22693-    '    yk = y[k];\n'+
22694-    body+'\n'+
22695-    '    Zv[j] = zk;\n'+
22696-    '  }\n'+
22697-    '  j0 = Xi[i]; j1 = Xi[i+1];\n'+
22698-    '  for(j=j0;j!==j1;++j) x[Xj[j]] = 0;\n'+
22699-    '  j0 = Yi[i]; j1 = Yi[i+1];\n'+
22700-    '  for(j=j0;j!==j1;++j) y[Yj[j]] = 0;\n'+
22701-    '}\n'+
22702-    'return [Zi,Zj,Zv];'
22703-  );
22704-};
22705-
22706-(function() {
22707-  var k,A,B,C;
22708-  for(k in numeric.ops2) {
22709-    if(isFinite(eval('1'+numeric.ops2[k]+'0'))) A = '[Y[0],Y[1],numeric.'+k+'(X,Y[2])]';
22710-    else A = 'NaN';
22711-    if(isFinite(eval('0'+numeric.ops2[k]+'1'))) B = '[X[0],X[1],numeric.'+k+'(X[2],Y)]';
22712-    else B = 'NaN';
22713-    if(isFinite(eval('1'+numeric.ops2[k]+'0')) && isFinite(eval('0'+numeric.ops2[k]+'1'))) C = 'numeric.ccs'+k+'MM(X,Y)';
22714-    else C = 'NaN';
22715-    numeric['ccs'+k+'MM'] = numeric.ccsbinop('zk = xk '+numeric.ops2[k]+'yk;');
22716-    numeric['ccs'+k] = Function('X','Y',
22717-      'if(typeof X === "number") return '+A+';\n'+
22718-      'if(typeof Y === "number") return '+B+';\n'+
22719-      'return '+C+';\n'
22720-    );
22721-  }
22722-}());
22723-
22724-numeric.ccsScatter = function ccsScatter(A) {
22725-  var Ai = A[0], Aj = A[1], Av = A[2];
22726-  var n = numeric.sup(Aj)+1,m=Ai.length;
22727-  var Ri = numeric.rep([n],0),Rj=Array(m), Rv = Array(m);
22728-  var counts = numeric.rep([n],0),i;
22729-  for(i=0;i<m;++i) counts[Aj[i]]++;
22730-  for(i=0;i<n;++i) Ri[i+1] = Ri[i] + counts[i];
22731-  var ptr = Ri.slice(0),k,Aii;
22732-  for(i=0;i<m;++i) {
22733-    Aii = Aj[i];
22734-    k = ptr[Aii];
22735-    Rj[k] = Ai[i];
22736-    Rv[k] = Av[i];
22737-    ptr[Aii]=ptr[Aii]+1;
22738-  }
22739-  return [Ri,Rj,Rv];
22740-}
22741-
22742-numeric.ccsGather = function ccsGather(A) {
22743-  var Ai = A[0], Aj = A[1], Av = A[2];
22744-  var n = Ai.length-1,m = Aj.length;
22745-  var Ri = Array(m), Rj = Array(m), Rv = Array(m);
22746-  var i,j,j0,j1,p;
22747-  p=0;
22748-  for(i=0;i<n;++i) {
22749-    j0 = Ai[i];
22750-    j1 = Ai[i+1];
22751-    for(j=j0;j!==j1;++j) {
22752-      Rj[p] = i;
22753-      Ri[p] = Aj[j];
22754-      Rv[p] = Av[j];
22755-      ++p;
22756-    }
22757-  }
22758-  return [Ri,Rj,Rv];
22759-}
22760-
22761-// The following sparse linear algebra routines are deprecated.
22762-
22763-numeric.sdim = function dim(A,ret,k) {
22764-  if(typeof ret === "undefined") { ret = []; }
22765-  if(typeof A !== "object") return ret;
22766-  if(typeof k === "undefined") { k=0; }
22767-  if(!(k in ret)) { ret[k] = 0; }
22768-  if(A.length > ret[k]) ret[k] = A.length;
22769-  var i;
22770-  for(i in A) {
22771-    if(A.hasOwnProperty(i)) dim(A[i],ret,k+1);
22772-  }
22773-  return ret;
22774-};
22775-
22776-numeric.sclone = function clone(A,k,n) {
22777-  if(typeof k === "undefined") { k=0; }
22778-  if(typeof n === "undefined") { n = numeric.sdim(A).length; }
22779-  var i,ret = Array(A.length);
22780-  if(k === n-1) {
22781-    for(i in A) { if(A.hasOwnProperty(i)) ret[i] = A[i]; }
22782-    return ret;
22783-  }
22784-  for(i in A) {
22785-    if(A.hasOwnProperty(i)) ret[i] = clone(A[i],k+1,n);
22786-  }
22787-  return ret;
22788-}
22789-
22790-numeric.sdiag = function diag(d) {
22791-  var n = d.length,i,ret = Array(n),i1,i2,i3;
22792-  for(i=n-1;i>=1;i-=2) {
22793-    i1 = i-1;
22794-    ret[i] = []; ret[i][i] = d[i];
22795-    ret[i1] = []; ret[i1][i1] = d[i1];
22796-  }
22797-  if(i===0) { ret[0] = []; ret[0][0] = d[i]; }
22798-  return ret;
22799-}
22800-
22801-numeric.sidentity = function identity(n) { return numeric.sdiag(numeric.rep([n],1)); }
22802-
22803-numeric.stranspose = function transpose(A) {
22804-  var ret = [], n = A.length, i,j,Ai;
22805-  for(i in A) {
22806-    if(!(A.hasOwnProperty(i))) continue;
22807-    Ai = A[i];
22808-    for(j in Ai) {
22809-      if(!(Ai.hasOwnProperty(j))) continue;
22810-      if(typeof ret[j] !== "object") { ret[j] = []; }
22811-      ret[j][i] = Ai[j];
22812-    }
22813-  }
22814-  return ret;
22815-}
22816-
22817-numeric.sLUP = function LUP(A,tol) {
22818-  throw new Error("The function numeric.sLUP had a bug in it and has been removed. Please use the new numeric.ccsLUP function instead.");
22819-};
22820-
22821-numeric.sdotMM = function dotMM(A,B) {
22822-  var p = A.length, q = B.length, BT = numeric.stranspose(B), r = BT.length, Ai, BTk;
22823-  var i,j,k,accum;
22824-  var ret = Array(p),reti;
22825-  for(i=p-1;i>=0;i--) {
22826-    reti = [];
22827-    Ai = A[i];
22828-    for(k=r-1;k>=0;k--) {
22829-      accum = 0;
22830-      BTk = BT[k];
22831-      for(j in Ai) {
22832-        if(!(Ai.hasOwnProperty(j))) continue;
22833-        if(j in BTk) { accum += Ai[j]*BTk[j]; }
22834-      }
22835-      if(accum) reti[k] = accum;
22836-    }
22837-    ret[i] = reti;
22838-  }
22839-  return ret;
22840-}
22841-
22842-numeric.sdotMV = function dotMV(A,x) {
22843-  var p = A.length, Ai, i,j;
22844-  var ret = Array(p), accum;
22845-  for(i=p-1;i>=0;i--) {
22846-    Ai = A[i];
22847-    accum = 0;
22848-    for(j in Ai) {
22849-      if(!(Ai.hasOwnProperty(j))) continue;
22850-      if(x[j]) accum += Ai[j]*x[j];
22851-    }
22852-    if(accum) ret[i] = accum;
22853-  }
22854-  return ret;
22855-}
22856-
22857-numeric.sdotVM = function dotMV(x,A) {
22858-  var i,j,Ai,alpha;
22859-  var ret = [], accum;
22860-  for(i in x) {
22861-    if(!x.hasOwnProperty(i)) continue;
22862-    Ai = A[i];
22863-    alpha = x[i];
22864-    for(j in Ai) {
22865-      if(!Ai.hasOwnProperty(j)) continue;
22866-      if(!ret[j]) { ret[j] = 0; }
22867-      ret[j] += alpha*Ai[j];
22868-    }
22869-  }
22870-  return ret;
22871-}
22872-
22873-numeric.sdotVV = function dotVV(x,y) {
22874-  var i,ret=0;
22875-  for(i in x) { if(x[i] && y[i]) ret+= x[i]*y[i]; }
22876-  return ret;
22877-}
22878-
22879-numeric.sdot = function dot(A,B) {
22880-  var m = numeric.sdim(A).length, n = numeric.sdim(B).length;
22881-  var k = m*1000+n;
22882-  switch(k) {
22883-    case 0: return A*B;
22884-    case 1001: return numeric.sdotVV(A,B);
22885-    case 2001: return numeric.sdotMV(A,B);
22886-    case 1002: return numeric.sdotVM(A,B);
22887-    case 2002: return numeric.sdotMM(A,B);
22888-    default: throw new Error('numeric.sdot not implemented for tensors of order '+m+' and '+n);
22889-  }
22890-}
22891-
22892-numeric.sscatter = function scatter(V) {
22893-  var n = V[0].length, Vij, i, j, m = V.length, A = [], Aj;
22894-  for(i=n-1;i>=0;--i) {
22895-    if(!V[m-1][i]) continue;
22896-    Aj = A;
22897-    for(j=0;j<m-2;j++) {
22898-      Vij = V[j][i];
22899-      if(!Aj[Vij]) Aj[Vij] = [];
22900-      Aj = Aj[Vij];
22901-    }
22902-    Aj[V[j][i]] = V[j+1][i];
22903-  }
22904-  return A;
22905-}
22906-
22907-numeric.sgather = function gather(A,ret,k) {
22908-  if(typeof ret === "undefined") ret = [];
22909-  if(typeof k === "undefined") k = [];
22910-  var n,i,Ai;
22911-  n = k.length;
22912-  for(i in A) {
22913-    if(A.hasOwnProperty(i)) {
22914-      k[n] = parseInt(i);
22915-      Ai = A[i];
22916-      if(typeof Ai === "number") {
22917-        if(Ai) {
22918-          if(ret.length === 0) {
22919-            for(i=n+1;i>=0;--i) ret[i] = [];
22920-          }
22921-          for(i=n;i>=0;--i) ret[i].push(k[i]);
22922-          ret[n+1].push(Ai);
22923-        }
22924-      } else gather(Ai,ret,k);
22925-    }
22926-  }
22927-  if(k.length>n) k.pop();
22928-  return ret;
22929-}
22930-
22931-// 6. Coordinate matrices
22932-numeric.cLU = function LU(A) {
22933-  var I = A[0], J = A[1], V = A[2];
22934-  var p = I.length, m=0, i,j,k,a,b,c;
22935-  for(i=0;i<p;i++) if(I[i]>m) m=I[i];
22936-  m++;
22937-  var L = Array(m), U = Array(m), left = numeric.rep([m],Infinity), right = numeric.rep([m],-Infinity);
22938-  var Ui, Uj,alpha;
22939-  for(k=0;k<p;k++) {
22940-    i = I[k];
22941-    j = J[k];
22942-    if(j<left[i]) left[i] = j;
22943-    if(j>right[i]) right[i] = j;
22944-  }
22945-  for(i=0;i<m-1;i++) { if(right[i] > right[i+1]) right[i+1] = right[i]; }
22946-  for(i=m-1;i>=1;i--) { if(left[i]<left[i-1]) left[i-1] = left[i]; }
22947-  var countL = 0, countU = 0;
22948-  for(i=0;i<m;i++) {
22949-    U[i] = numeric.rep([right[i]-left[i]+1],0);
22950-    L[i] = numeric.rep([i-left[i]],0);
22951-    countL += i-left[i]+1;
22952-    countU += right[i]-i+1;
22953-  }
22954-  for(k=0;k<p;k++) { i = I[k]; U[i][J[k]-left[i]] = V[k]; }
22955-  for(i=0;i<m-1;i++) {
22956-    a = i-left[i];
22957-    Ui = U[i];
22958-    for(j=i+1;left[j]<=i && j<m;j++) {
22959-      b = i-left[j];
22960-      c = right[i]-i;
22961-      Uj = U[j];
22962-      alpha = Uj[b]/Ui[a];
22963-      if(alpha) {
22964-        for(k=1;k<=c;k++) { Uj[k+b] -= alpha*Ui[k+a]; }
22965-        L[j][i-left[j]] = alpha;
22966-      }
22967-    }
22968-  }
22969-  var Ui = [], Uj = [], Uv = [], Li = [], Lj = [], Lv = [];
22970-  var p,q,foo;
22971-  p=0; q=0;
22972-  for(i=0;i<m;i++) {
22973-    a = left[i];
22974-    b = right[i];
22975-    foo = U[i];
22976-    for(j=i;j<=b;j++) {
22977-      if(foo[j-a]) {
22978-        Ui[p] = i;
22979-        Uj[p] = j;
22980-        Uv[p] = foo[j-a];
22981-        p++;
22982-      }
22983-    }
22984-    foo = L[i];
22985-    for(j=a;j<i;j++) {
22986-      if(foo[j-a]) {
22987-        Li[q] = i;
22988-        Lj[q] = j;
22989-        Lv[q] = foo[j-a];
22990-        q++;
22991-      }
22992-    }
22993-    Li[q] = i;
22994-    Lj[q] = i;
22995-    Lv[q] = 1;
22996-    q++;
22997-  }
22998-  return {U:[Ui,Uj,Uv], L:[Li,Lj,Lv]};
22999-};
23000-
23001-numeric.cLUsolve = function LUsolve(lu,b) {
23002-  var L = lu.L, U = lu.U, ret = numeric.clone(b);
23003-  var Li = L[0], Lj = L[1], Lv = L[2];
23004-  var Ui = U[0], Uj = U[1], Uv = U[2];
23005-  var p = Ui.length, q = Li.length;
23006-  var m = ret.length,i,j,k;
23007-  k = 0;
23008-  for(i=0;i<m;i++) {
23009-    while(Lj[k] < i) {
23010-      ret[i] -= Lv[k]*ret[Lj[k]];
23011-      k++;
23012-    }
23013-    k++;
23014-  }
23015-  k = p-1;
23016-  for(i=m-1;i>=0;i--) {
23017-    while(Uj[k] > i) {
23018-      ret[i] -= Uv[k]*ret[Uj[k]];
23019-      k--;
23020-    }
23021-    ret[i] /= Uv[k];
23022-    k--;
23023-  }
23024-  return ret;
23025-};
23026-
23027-numeric.cgrid = function grid(n,shape) {
23028-  if(typeof n === "number") n = [n,n];
23029-  var ret = numeric.rep(n,-1);
23030-  var i,j,count;
23031-  if(typeof shape !== "function") {
23032-    switch(shape) {
23033-      case 'L':
23034-        shape = function(i,j) { return (i>=n[0]/2 || j<n[1]/2); }
23035-        break;
23036-      default:
23037-        shape = function(i,j) { return true; };
23038-        break;
23039-    }
23040-  }
23041-  count=0;
23042-  for(i=1;i<n[0]-1;i++) for(j=1;j<n[1]-1;j++)
23043-    if(shape(i,j)) {
23044-      ret[i][j] = count;
23045-      count++;
23046-    }
23047-  return ret;
23048-}
23049-
23050-numeric.cdelsq = function delsq(g) {
23051-  var dir = [[-1,0],[0,-1],[0,1],[1,0]];
23052-  var s = numeric.dim(g), m = s[0], n = s[1], i,j,k,p,q;
23053-  var Li = [], Lj = [], Lv = [];
23054-  for(i=1;i<m-1;i++) for(j=1;j<n-1;j++) {
23055-    if(g[i][j]<0) continue;
23056-    for(k=0;k<4;k++) {
23057-      p = i+dir[k][0];
23058-      q = j+dir[k][1];
23059-      if(g[p][q]<0) continue;
23060-      Li.push(g[i][j]);
23061-      Lj.push(g[p][q]);
23062-      Lv.push(-1);
23063-    }
23064-    Li.push(g[i][j]);
23065-    Lj.push(g[i][j]);
23066-    Lv.push(4);
23067-  }
23068-  return [Li,Lj,Lv];
23069-}
23070-
23071-numeric.cdotMV = function dotMV(A,x) {
23072-  var ret, Ai = A[0], Aj = A[1], Av = A[2],k,p=Ai.length,N;
23073-  N=0;
23074-  for(k=0;k<p;k++) { if(Ai[k]>N) N = Ai[k]; }
23075-  N++;
23076-  ret = numeric.rep([N],0);
23077-  for(k=0;k<p;k++) { ret[Ai[k]]+=Av[k]*x[Aj[k]]; }
23078-  return ret;
23079-}
23080-
23081-// 7. Splines
23082-
23083-numeric.Spline = function Spline(x,yl,yr,kl,kr) { this.x = x; this.yl = yl; this.yr = yr; this.kl = kl; this.kr = kr; }
23084-numeric.Spline.prototype._at = function _at(x1,p) {
23085-  var x = this.x;
23086-  var yl = this.yl;
23087-  var yr = this.yr;
23088-  var kl = this.kl;
23089-  var kr = this.kr;
23090-  var x1,a,b,t;
23091-  var add = numeric.add, sub = numeric.sub, mul = numeric.mul;
23092-  a = sub(mul(kl[p],x[p+1]-x[p]),sub(yr[p+1],yl[p]));
23093-  b = add(mul(kr[p+1],x[p]-x[p+1]),sub(yr[p+1],yl[p]));
23094-  t = (x1-x[p])/(x[p+1]-x[p]);
23095-  var s = t*(1-t);
23096-  return add(add(add(mul(1-t,yl[p]),mul(t,yr[p+1])),mul(a,s*(1-t))),mul(b,s*t));
23097-}
23098-numeric.Spline.prototype.at = function at(x0) {
23099-  if(typeof x0 === "number") {
23100-    var x = this.x;
23101-    var n = x.length;
23102-    var p,q,mid,floor = Math.floor,a,b,t;
23103-    p = 0;
23104-    q = n-1;
23105-    while(q-p>1) {
23106-      mid = floor((p+q)/2);
23107-      if(x[mid] <= x0) p = mid;
23108-      else q = mid;
23109-    }
23110-    return this._at(x0,p);
23111-  }
23112-  var n = x0.length, i, ret = Array(n);
23113-  for(i=n-1;i!==-1;--i) ret[i] = this.at(x0[i]);
23114-  return ret;
23115-}
23116-numeric.Spline.prototype.diff = function diff() {
23117-  var x = this.x;
23118-  var yl = this.yl;
23119-  var yr = this.yr;
23120-  var kl = this.kl;
23121-  var kr = this.kr;
23122-  var n = yl.length;
23123-  var i,dx,dy;
23124-  var zl = kl, zr = kr, pl = Array(n), pr = Array(n);
23125-  var add = numeric.add, mul = numeric.mul, div = numeric.div, sub = numeric.sub;
23126-  for(i=n-1;i!==-1;--i) {
23127-    dx = x[i+1]-x[i];
23128-    dy = sub(yr[i+1],yl[i]);
23129-    pl[i] = div(add(mul(dy, 6),mul(kl[i],-4*dx),mul(kr[i+1],-2*dx)),dx*dx);
23130-    pr[i+1] = div(add(mul(dy,-6),mul(kl[i], 2*dx),mul(kr[i+1], 4*dx)),dx*dx);
23131-  }
23132-  return new numeric.Spline(x,zl,zr,pl,pr);
23133-}
23134-numeric.Spline.prototype.roots = function roots() {
23135-  function sqr(x) { return x*x; }
23136-  function heval(y0,y1,k0,k1,x) {
23137-    var A = k0*2-(y1-y0);
23138-    var B = -k1*2+(y1-y0);
23139-    var t = (x+1)*0.5;
23140-    var s = t*(1-t);
23141-    return (1-t)*y0+t*y1+A*s*(1-t)+B*s*t;
23142-  }
23143-  var ret = [];
23144-  var x = this.x, yl = this.yl, yr = this.yr, kl = this.kl, kr = this.kr;
23145-  if(typeof yl[0] === "number") {
23146-    yl = [yl];
23147-    yr = [yr];
23148-    kl = [kl];
23149-    kr = [kr];
23150-  }
23151-  var m = yl.length,n=x.length-1,i,j,k,y,s,t;
23152-  var ai,bi,ci,di, ret = Array(m),ri,k0,k1,y0,y1,A,B,D,dx,cx,stops,z0,z1,zm,t0,t1,tm;
23153-  var sqrt = Math.sqrt;
23154-  for(i=0;i!==m;++i) {
23155-    ai = yl[i];
23156-    bi = yr[i];
23157-    ci = kl[i];
23158-    di = kr[i];
23159-    ri = [];
23160-    for(j=0;j!==n;j++) {
23161-      if(j>0 && bi[j]*ai[j]<0) ri.push(x[j]);
23162-      dx = (x[j+1]-x[j]);
23163-      cx = x[j];
23164-      y0 = ai[j];
23165-      y1 = bi[j+1];
23166-      k0 = ci[j]/dx;
23167-      k1 = di[j+1]/dx;
23168-      D = sqr(k0-k1+3*(y0-y1)) + 12*k1*y0;
23169-      A = k1+3*y0+2*k0-3*y1;
23170-      B = 3*(k1+k0+2*(y0-y1));
23171-      if(D<=0) {
23172-        z0 = A/B;
23173-        if(z0>x[j] && z0<x[j+1]) stops = [x[j],z0,x[j+1]];
23174-        else stops = [x[j],x[j+1]];
23175-      } else {
23176-        z0 = (A-sqrt(D))/B;
23177-        z1 = (A+sqrt(D))/B;
23178-        stops = [x[j]];
23179-        if(z0>x[j] && z0<x[j+1]) stops.push(z0);
23180-        if(z1>x[j] && z1<x[j+1]) stops.push(z1);
23181-        stops.push(x[j+1]);
23182-      }
23183-      t0 = stops[0];
23184-      z0 = this._at(t0,j);
23185-      for(k=0;k<stops.length-1;k++) {
23186-        t1 = stops[k+1];
23187-        z1 = this._at(t1,j);
23188-        if(z0 === 0) {
23189-          ri.push(t0);
23190-          t0 = t1;
23191-          z0 = z1;
23192-          continue;
23193-        }
23194-        if(z1 === 0 || z0*z1>0) {
23195-          t0 = t1;
23196-          z0 = z1;
23197-          continue;
23198-        }
23199-        var side = 0;
23200-        while(1) {
23201-          tm = (z0*t1-z1*t0)/(z0-z1);
23202-          if(tm <= t0 || tm >= t1) { break; }
23203-          zm = this._at(tm,j);
23204-          if(zm*z1>0) {
23205-            t1 = tm;
23206-            z1 = zm;
23207-            if(side === -1) z0*=0.5;
23208-            side = -1;
23209-          } else if(zm*z0>0) {
23210-            t0 = tm;
23211-            z0 = zm;
23212-            if(side === 1) z1*=0.5;
23213-            side = 1;
23214-          } else break;
23215-        }
23216-        ri.push(tm);
23217-        t0 = stops[k+1];
23218-        z0 = this._at(t0, j);
23219-      }
23220-      if(z1 === 0) ri.push(t1);
23221-    }
23222-    ret[i] = ri;
23223-  }
23224-  if(typeof this.yl[0] === "number") return ret[0];
23225-  return ret;
23226-}
23227-numeric.spline = function spline(x,y,k1,kn) {
23228-  var n = x.length, b = [], dx = [], dy = [];
23229-  var i;
23230-  var sub = numeric.sub,mul = numeric.mul,add = numeric.add;
23231-  for(i=n-2;i>=0;i--) { dx[i] = x[i+1]-x[i]; dy[i] = sub(y[i+1],y[i]); }
23232-  if(typeof k1 === "string" || typeof kn === "string") {
23233-    k1 = kn = "periodic";
23234-  }
23235-  // Build sparse tridiagonal system
23236-  var T = [[],[],[]];
23237-  switch(typeof k1) {
23238-    case "undefined":
23239-      b[0] = mul(3/(dx[0]*dx[0]),dy[0]);
23240-      T[0].push(0,0);
23241-      T[1].push(0,1);
23242-      T[2].push(2/dx[0],1/dx[0]);
23243-      break;
23244-    case "string":
23245-      b[0] = add(mul(3/(dx[n-2]*dx[n-2]),dy[n-2]),mul(3/(dx[0]*dx[0]),dy[0]));
23246-      T[0].push(0,0,0);
23247-      T[1].push(n-2,0,1);
23248-      T[2].push(1/dx[n-2],2/dx[n-2]+2/dx[0],1/dx[0]);
23249-      break;
23250-    default:
23251-      b[0] = k1;
23252-      T[0].push(0);
23253-      T[1].push(0);
23254-      T[2].push(1);
23255-      break;
23256-  }
23257-  for(i=1;i<n-1;i++) {
23258-    b[i] = add(mul(3/(dx[i-1]*dx[i-1]),dy[i-1]),mul(3/(dx[i]*dx[i]),dy[i]));
23259-    T[0].push(i,i,i);
23260-    T[1].push(i-1,i,i+1);
23261-    T[2].push(1/dx[i-1],2/dx[i-1]+2/dx[i],1/dx[i]);
23262-  }
23263-  switch(typeof kn) {
23264-    case "undefined":
23265-      b[n-1] = mul(3/(dx[n-2]*dx[n-2]),dy[n-2]);
23266-      T[0].push(n-1,n-1);
23267-      T[1].push(n-2,n-1);
23268-      T[2].push(1/dx[n-2],2/dx[n-2]);
23269-      break;
23270-    case "string":
23271-      T[1][T[1].length-1] = 0;
23272-      break;
23273-    default:
23274-      b[n-1] = kn;
23275-      T[0].push(n-1);
23276-      T[1].push(n-1);
23277-      T[2].push(1);
23278-      break;
23279-  }
23280-  if(typeof b[0] !== "number") b = numeric.transpose(b);
23281-  else b = [b];
23282-  var k = Array(b.length);
23283-  if(typeof k1 === "string") {
23284-    for(i=k.length-1;i!==-1;--i) {
23285-      k[i] = numeric.ccsLUPSolve(numeric.ccsLUP(numeric.ccsScatter(T)),b[i]);
23286-      k[i][n-1] = k[i][0];
23287-    }
23288-  } else {
23289-    for(i=k.length-1;i!==-1;--i) {
23290-      k[i] = numeric.cLUsolve(numeric.cLU(T),b[i]);
23291-    }
23292-  }
23293-  if(typeof y[0] === "number") k = k[0];
23294-  else k = numeric.transpose(k);
23295-  return new numeric.Spline(x,y,y,k,k);
23296-}
23297-
23298-// 8. FFT
23299-numeric.fftpow2 = function fftpow2(x,y) {
23300-  var n = x.length;
23301-  if(n === 1) return;
23302-  var cos = Math.cos, sin = Math.sin, i,j;
23303-  var xe = Array(n/2), ye = Array(n/2), xo = Array(n/2), yo = Array(n/2);
23304-  j = n/2;
23305-  for(i=n-1;i!==-1;--i) {
23306-    --j;
23307-    xo[j] = x[i];
23308-    yo[j] = y[i];
23309-    --i;
23310-    xe[j] = x[i];
23311-    ye[j] = y[i];
23312-  }
23313-  fftpow2(xe,ye);
23314-  fftpow2(xo,yo);
23315-  j = n/2;
23316-  var t,k = (-6.2831853071795864769252867665590057683943387987502116419/n),ci,si;
23317-  for(i=n-1;i!==-1;--i) {
23318-    --j;
23319-    if(j === -1) j = n/2-1;
23320-    t = k*i;
23321-    ci = cos(t);
23322-    si = sin(t);
23323-    x[i] = xe[j] + ci*xo[j] - si*yo[j];
23324-    y[i] = ye[j] + ci*yo[j] + si*xo[j];
23325-  }
23326-}
23327-numeric._ifftpow2 = function _ifftpow2(x,y) {
23328-  var n = x.length;
23329-  if(n === 1) return;
23330-  var cos = Math.cos, sin = Math.sin, i,j;
23331-  var xe = Array(n/2), ye = Array(n/2), xo = Array(n/2), yo = Array(n/2);
23332-  j = n/2;
23333-  for(i=n-1;i!==-1;--i) {
23334-    --j;
23335-    xo[j] = x[i];
23336-    yo[j] = y[i];
23337-    --i;
23338-    xe[j] = x[i];
23339-    ye[j] = y[i];
23340-  }
23341-  _ifftpow2(xe,ye);
23342-  _ifftpow2(xo,yo);
23343-  j = n/2;
23344-  var t,k = (6.2831853071795864769252867665590057683943387987502116419/n),ci,si;
23345-  for(i=n-1;i!==-1;--i) {
23346-    --j;
23347-    if(j === -1) j = n/2-1;
23348-    t = k*i;
23349-    ci = cos(t);
23350-    si = sin(t);
23351-    x[i] = xe[j] + ci*xo[j] - si*yo[j];
23352-    y[i] = ye[j] + ci*yo[j] + si*xo[j];
23353-  }
23354-}
23355-numeric.ifftpow2 = function ifftpow2(x,y) {
23356-  numeric._ifftpow2(x,y);
23357-  numeric.diveq(x,x.length);
23358-  numeric.diveq(y,y.length);
23359-}
23360-numeric.convpow2 = function convpow2(ax,ay,bx,by) {
23361-  numeric.fftpow2(ax,ay);
23362-  numeric.fftpow2(bx,by);
23363-  var i,n = ax.length,axi,bxi,ayi,byi;
23364-  for(i=n-1;i!==-1;--i) {
23365-    axi = ax[i]; ayi = ay[i]; bxi = bx[i]; byi = by[i];
23366-    ax[i] = axi*bxi-ayi*byi;
23367-    ay[i] = axi*byi+ayi*bxi;
23368-  }
23369-  numeric.ifftpow2(ax,ay);
23370-}
23371-numeric.T.prototype.fft = function fft() {
23372-  var x = this.x, y = this.y;
23373-  var n = x.length, log = Math.log, log2 = log(2),
23374-    p = Math.ceil(log(2*n-1)/log2), m = Math.pow(2,p);
23375-  var cx = numeric.rep([m],0), cy = numeric.rep([m],0), cos = Math.cos, sin = Math.sin;
23376-  var k, c = (-3.141592653589793238462643383279502884197169399375105820/n),t;
23377-  var a = numeric.rep([m],0), b = numeric.rep([m],0),nhalf = Math.floor(n/2);
23378-  for(k=0;k<n;k++) a[k] = x[k];
23379-  if(typeof y !== "undefined") for(k=0;k<n;k++) b[k] = y[k];
23380-  cx[0] = 1;
23381-  for(k=1;k<=m/2;k++) {
23382-    t = c*k*k;
23383-    cx[k] = cos(t);
23384-    cy[k] = sin(t);
23385-    cx[m-k] = cos(t);
23386-    cy[m-k] = sin(t)
23387-  }
23388-  var X = new numeric.T(a,b), Y = new numeric.T(cx,cy);
23389-  X = X.mul(Y);
23390-  numeric.convpow2(X.x,X.y,numeric.clone(Y.x),numeric.neg(Y.y));
23391-  X = X.mul(Y);
23392-  X.x.length = n;
23393-  X.y.length = n;
23394-  return X;
23395-}
23396-numeric.T.prototype.ifft = function ifft() {
23397-  var x = this.x, y = this.y;
23398-  var n = x.length, log = Math.log, log2 = log(2),
23399-    p = Math.ceil(log(2*n-1)/log2), m = Math.pow(2,p);
23400-  var cx = numeric.rep([m],0), cy = numeric.rep([m],0), cos = Math.cos, sin = Math.sin;
23401-  var k, c = (3.141592653589793238462643383279502884197169399375105820/n),t;
23402-  var a = numeric.rep([m],0), b = numeric.rep([m],0),nhalf = Math.floor(n/2);
23403-  for(k=0;k<n;k++) a[k] = x[k];
23404-  if(typeof y !== "undefined") for(k=0;k<n;k++) b[k] = y[k];
23405-  cx[0] = 1;
23406-  for(k=1;k<=m/2;k++) {
23407-    t = c*k*k;
23408-    cx[k] = cos(t);
23409-    cy[k] = sin(t);
23410-    cx[m-k] = cos(t);
23411-    cy[m-k] = sin(t)
23412-  }
23413-  var X = new numeric.T(a,b), Y = new numeric.T(cx,cy);
23414-  X = X.mul(Y);
23415-  numeric.convpow2(X.x,X.y,numeric.clone(Y.x),numeric.neg(Y.y));
23416-  X = X.mul(Y);
23417-  X.x.length = n;
23418-  X.y.length = n;
23419-  return X.div(n);
23420-}
23421-
23422-//9. Unconstrained optimization
23423-numeric.gradient = function gradient(f,x) {
23424-  var n = x.length;
23425-  var f0 = f(x);
23426-  if(isNaN(f0)) throw new Error('gradient: f(x) is a NaN!');
23427-  var max = Math.max;
23428-  var i,x0 = numeric.clone(x),f1,f2, J = Array(n);
23429-  var div = numeric.div, sub = numeric.sub,errest,roundoff,max = Math.max,eps = 1e-3,abs = Math.abs, min = Math.min;
23430-  var t0,t1,t2,it=0,d1,d2,N;
23431-  for(i=0;i<n;i++) {
23432-    var h = max(1e-6*f0,1e-8);
23433-    while(1) {
23434-      ++it;
23435-      if(it>20) { throw new Error("Numerical gradient fails"); }
23436-      x0[i] = x[i]+h;
23437-      f1 = f(x0);
23438-      x0[i] = x[i]-h;
23439-      f2 = f(x0);
23440-      x0[i] = x[i];
23441-      if(isNaN(f1) || isNaN(f2)) { h/=16; continue; }
23442-      J[i] = (f1-f2)/(2*h);
23443-      t0 = x[i]-h;
23444-      t1 = x[i];
23445-      t2 = x[i]+h;
23446-      d1 = (f1-f0)/h;
23447-      d2 = (f0-f2)/h;
23448-      N = max(abs(J[i]),abs(f0),abs(f1),abs(f2),abs(t0),abs(t1),abs(t2),1e-8);
23449-      errest = min(max(abs(d1-J[i]),abs(d2-J[i]),abs(d1-d2))/N,h/N);
23450-      if(errest>eps) { h/=16; }
23451-      else break;
23452-    }
23453-  }
23454-  return J;
23455-}
23456-
23457-numeric.uncmin = function uncmin(f,x0,tol,gradient,maxit,callback,options) {
23458-  var grad = numeric.gradient;
23459-  if(typeof options === "undefined") { options = {}; }
23460-  if(typeof tol === "undefined") { tol = 1e-8; }
23461-  if(typeof gradient === "undefined") { gradient = function(x) { return grad(f,x); }; }
23462-  if(typeof maxit === "undefined") maxit = 1000;
23463-  x0 = numeric.clone(x0);
23464-  var n = x0.length;
23465-  var f0 = f(x0),f1,df0;
23466-  if(isNaN(f0)) throw new Error('uncmin: f(x0) is a NaN!');
23467-  var max = Math.max, norm2 = numeric.norm2;
23468-  tol = max(tol,numeric.epsilon);
23469-  var step,g0,g1,H1 = options.Hinv || numeric.identity(n);
23470-  var dot = numeric.dot, inv = numeric.inv, sub = numeric.sub, add = numeric.add, ten = numeric.tensor, div = numeric.div, mul = numeric.mul;
23471-  var all = numeric.all, isfinite = numeric.isFinite, neg = numeric.neg;
23472-  var it=0,i,s,x1,y,Hy,Hs,ys,i0,t,nstep,t1,t2;
23473-  var msg = "";
23474-  g0 = gradient(x0);
23475-  while(it<maxit) {
23476-    if(typeof callback === "function") { if(callback(it,x0,f0,g0,H1)) { msg = "Callback returned true"; break; } }
23477-    if(!all(isfinite(g0))) { msg = "Gradient has Infinity or NaN"; break; }
23478-    step = neg(dot(H1,g0));
23479-    if(!all(isfinite(step))) { msg = "Search direction has Infinity or NaN"; break; }
23480-    nstep = norm2(step);
23481-    if(nstep < tol) { msg="Newton step smaller than tol"; break; }
23482-    t = 1;
23483-    df0 = dot(g0,step);
23484-    // line search
23485-    x1 = x0;
23486-    while(it < maxit) {
23487-      if(t*nstep < tol) { break; }
23488-      s = mul(step,t);
23489-      x1 = add(x0,s);
23490-      f1 = f(x1);
23491-      if(f1-f0 >= 0.1*t*df0 || isNaN(f1)) {
23492-        t *= 0.5;
23493-        ++it;
23494-        continue;
23495-      }
23496-      break;
23497-    }
23498-    if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; }
23499-    if(it === maxit) { msg = "maxit reached during line search"; break; }
23500-    g1 = gradient(x1);
23501-    y = sub(g1,g0);
23502-    ys = dot(y,s);
23503-    Hy = dot(H1,y);
23504-    H1 = sub(add(H1,
23505-      mul(
23506-        (ys+dot(y,Hy))/(ys*ys),
23507-        ten(s,s)    )),
23508-      div(add(ten(Hy,s),ten(s,Hy)),ys));
23509-    x0 = x1;
23510-    f0 = f1;
23511-    g0 = g1;
23512-    ++it;
23513-  }
23514-  return {solution: x0, f: f0, gradient: g0, invHessian: H1, iterations:it, message: msg};
23515-}
23516-
23517-// 10. Ode solver (Dormand-Prince)
23518-numeric.Dopri = function Dopri(x,y,f,ymid,iterations,msg,events) {
23519-  this.x = x;
23520-  this.y = y;
23521-  this.f = f;
23522-  this.ymid = ymid;
23523-  this.iterations = iterations;
23524-  this.events = events;
23525-  this.message = msg;
23526-}
23527-numeric.Dopri.prototype._at = function _at(xi,j) {
23528-  function sqr(x) { return x*x; }
23529-  var sol = this;
23530-  var xs = sol.x;
23531-  var ys = sol.y;
23532-  var k1 = sol.f;
23533-  var ymid = sol.ymid;
23534-  var n = xs.length;
23535-  var x0,x1,xh,y0,y1,yh,xi;
23536-  var floor = Math.floor,h;
23537-  var c = 0.5;
23538-  var add = numeric.add, mul = numeric.mul,sub = numeric.sub, p,q,w;
23539-  x0 = xs[j];
23540-  x1 = xs[j+1];
23541-  y0 = ys[j];
23542-  y1 = ys[j+1];
23543-  h  = x1-x0;
23544-  xh = x0+c*h;
23545-  yh = ymid[j];
23546-  p = sub(k1[j  ],mul(y0,1/(x0-xh)+2/(x0-x1)));
23547-  q = sub(k1[j+1],mul(y1,1/(x1-xh)+2/(x1-x0)));
23548-  w = [sqr(xi - x1) * (xi - xh) / sqr(x0 - x1) / (x0 - xh),
23549-    sqr(xi - x0) * sqr(xi - x1) / sqr(x0 - xh) / sqr(x1 - xh),
23550-    sqr(xi - x0) * (xi - xh) / sqr(x1 - x0) / (x1 - xh),
23551-    (xi - x0) * sqr(xi - x1) * (xi - xh) / sqr(x0-x1) / (x0 - xh),
23552-    (xi - x1) * sqr(xi - x0) * (xi - xh) / sqr(x0-x1) / (x1 - xh)];
23553-  return add(add(add(add(mul(y0,w[0]),
23554-    mul(yh,w[1])),
23555-    mul(y1,w[2])),
23556-    mul( p,w[3])),
23557-    mul( q,w[4]));
23558-}
23559-numeric.Dopri.prototype.at = function at(x) {
23560-  var i,j,k,floor = Math.floor;
23561-  if(typeof x !== "number") {
23562-    var n = x.length, ret = Array(n);
23563-    for(i=n-1;i!==-1;--i) {
23564-      ret[i] = this.at(x[i]);
23565-    }
23566-    return ret;
23567-  }
23568-  var x0 = this.x;
23569-  i = 0; j = x0.length-1;
23570-  while(j-i>1) {
23571-    k = floor(0.5*(i+j));
23572-    if(x0[k] <= x) i = k;
23573-    else j = k;
23574-  }
23575-  return this._at(x,i);
23576-}
23577-
23578-numeric.dopri = function dopri(x0,x1,y0,f,tol,maxit,event) {
23579-  if(typeof tol === "undefined") { tol = 1e-6; }
23580-  if(typeof maxit === "undefined") { maxit = 1000; }
23581-  var xs = [x0], ys = [y0], k1 = [f(x0,y0)], k2,k3,k4,k5,k6,k7, ymid = [];
23582-  var A2 = 1/5;
23583-  var A3 = [3/40,9/40];
23584-  var A4 = [44/45,-56/15,32/9];
23585-  var A5 = [19372/6561,-25360/2187,64448/6561,-212/729];
23586-  var A6 = [9017/3168,-355/33,46732/5247,49/176,-5103/18656];
23587-  var b = [35/384,0,500/1113,125/192,-2187/6784,11/84];
23588-  var bm = [0.5*6025192743/30085553152,
23589-    0,
23590-    0.5*51252292925/65400821598,
23591-    0.5*-2691868925/45128329728,
23592-    0.5*187940372067/1594534317056,
23593-    0.5*-1776094331/19743644256,
23594-    0.5*11237099/235043384];
23595-  var c = [1/5,3/10,4/5,8/9,1,1];
23596-  var e = [-71/57600,0,71/16695,-71/1920,17253/339200,-22/525,1/40];
23597-  var i = 0,er,j;
23598-  var h = (x1-x0)/10;
23599-  var it = 0;
23600-  var add = numeric.add, mul = numeric.mul, y1,erinf;
23601-  var max = Math.max, min = Math.min, abs = Math.abs, norminf = numeric.norminf,pow = Math.pow;
23602-  var any = numeric.any, lt = numeric.lt, and = numeric.and, sub = numeric.sub;
23603-  var e0, e1, ev;
23604-  var ret = new numeric.Dopri(xs,ys,k1,ymid,-1,"");
23605-  if(typeof event === "function") e0 = event(x0,y0);
23606-  while(x0<x1 && it<maxit) {
23607-    ++it;
23608-    if(x0+h>x1) h = x1-x0;
23609-    k2 = f(x0+c[0]*h,                add(y0,mul(   A2*h,k1[i])));
23610-    k3 = f(x0+c[1]*h,            add(add(y0,mul(A3[0]*h,k1[i])),mul(A3[1]*h,k2)));
23611-    k4 = f(x0+c[2]*h,        add(add(add(y0,mul(A4[0]*h,k1[i])),mul(A4[1]*h,k2)),mul(A4[2]*h,k3)));
23612-    k5 = f(x0+c[3]*h,    add(add(add(add(y0,mul(A5[0]*h,k1[i])),mul(A5[1]*h,k2)),mul(A5[2]*h,k3)),mul(A5[3]*h,k4)));
23613-    k6 = f(x0+c[4]*h,add(add(add(add(add(y0,mul(A6[0]*h,k1[i])),mul(A6[1]*h,k2)),mul(A6[2]*h,k3)),mul(A6[3]*h,k4)),mul(A6[4]*h,k5)));
23614-    y1 = add(add(add(add(add(y0,mul(k1[i],h*b[0])),mul(k3,h*b[2])),mul(k4,h*b[3])),mul(k5,h*b[4])),mul(k6,h*b[5]));
23615-    k7 = f(x0+h,y1);
23616-    er = add(add(add(add(add(mul(k1[i],h*e[0]),mul(k3,h*e[2])),mul(k4,h*e[3])),mul(k5,h*e[4])),mul(k6,h*e[5])),mul(k7,h*e[6]));
23617-    if(typeof er === "number") erinf = abs(er);
23618-    else erinf = norminf(er);
23619-    if(erinf > tol) { // reject
23620-      h = 0.2*h*pow(tol/erinf,0.25);
23621-      if(x0+h === x0) {
23622-        ret.msg = "Step size became too small";
23623-        break;
23624-      }
23625-      continue;
23626-    }
23627-    ymid[i] = add(add(add(add(add(add(y0,
23628-      mul(k1[i],h*bm[0])),
23629-      mul(k3   ,h*bm[2])),
23630-      mul(k4   ,h*bm[3])),
23631-      mul(k5   ,h*bm[4])),
23632-      mul(k6   ,h*bm[5])),
23633-      mul(k7   ,h*bm[6]));
23634-    ++i;
23635-    xs[i] = x0+h;
23636-    ys[i] = y1;
23637-    k1[i] = k7;
23638-    if(typeof event === "function") {
23639-      var yi,xl = x0,xr = x0+0.5*h,xi;
23640-      e1 = event(xr,ymid[i-1]);
23641-      ev = and(lt(e0,0),lt(0,e1));
23642-      if(!any(ev)) { xl = xr; xr = x0+h; e0 = e1; e1 = event(xr,y1); ev = and(lt(e0,0),lt(0,e1)); }
23643-      if(any(ev)) {
23644-        var xc, yc, en,ei;
23645-        var side=0, sl = 1.0, sr = 1.0;
23646-        while(1) {
23647-          if(typeof e0 === "number") xi = (sr*e1*xl-sl*e0*xr)/(sr*e1-sl*e0);
23648-          else {
23649-            xi = xr;
23650-            for(j=e0.length-1;j!==-1;--j) {
23651-              if(e0[j]<0 && e1[j]>0) xi = min(xi,(sr*e1[j]*xl-sl*e0[j]*xr)/(sr*e1[j]-sl*e0[j]));
23652-            }
23653-          }
23654-          if(xi <= xl || xi >= xr) break;
23655-          yi = ret._at(xi, i-1);
23656-          ei = event(xi,yi);
23657-          en = and(lt(e0,0),lt(0,ei));
23658-          if(any(en)) {
23659-            xr = xi;
23660-            e1 = ei;
23661-            ev = en;
23662-            sr = 1.0;
23663-            if(side === -1) sl *= 0.5;
23664-            else sl = 1.0;
23665-            side = -1;
23666-          } else {
23667-            xl = xi;
23668-            e0 = ei;
23669-            sl = 1.0;
23670-            if(side === 1) sr *= 0.5;
23671-            else sr = 1.0;
23672-            side = 1;
23673-          }
23674-        }
23675-        y1 = ret._at(0.5*(x0+xi),i-1);
23676-        ret.f[i] = f(xi,yi);
23677-        ret.x[i] = xi;
23678-        ret.y[i] = yi;
23679-        ret.ymid[i-1] = y1;
23680-        ret.events = ev;
23681-        ret.iterations = it;
23682-        return ret;
23683-      }
23684-    }
23685-    x0 += h;
23686-    y0 = y1;
23687-    e0 = e1;
23688-    h = min(0.8*h*pow(tol/erinf,0.25),4*h);
23689-  }
23690-  ret.iterations = it;
23691-  return ret;
23692-}
23693-
23694-// 11. Ax = b
23695-numeric.LU = function(A, fast) {
23696-  fast = fast || false;
23697-
23698-  var abs = Math.abs;
23699-  var i, j, k, absAjk, Akk, Ak, Pk, Ai;
23700-  var max;
23701-  var n = A.length, n1 = n-1;
23702-  var P = new Array(n);
23703-  if(!fast) A = numeric.clone(A);
23704-
23705-  for (k = 0; k < n; ++k) {
23706-    Pk = k;
23707-    Ak = A[k];
23708-    max = abs(Ak[k]);
23709-    for (j = k + 1; j < n; ++j) {
23710-      absAjk = abs(A[j][k]);
23711-      if (max < absAjk) {
23712-        max = absAjk;
23713-        Pk = j;
23714-      }
23715-    }
23716-    P[k] = Pk;
23717-
23718-    if (Pk != k) {
23719-      A[k] = A[Pk];
23720-      A[Pk] = Ak;
23721-      Ak = A[k];
23722-    }
23723-
23724-    Akk = Ak[k];
23725-
23726-    for (i = k + 1; i < n; ++i) {
23727-      A[i][k] /= Akk;
23728-    }
23729-
23730-    for (i = k + 1; i < n; ++i) {
23731-      Ai = A[i];
23732-      for (j = k + 1; j < n1; ++j) {
23733-        Ai[j] -= Ai[k] * Ak[j];
23734-        ++j;
23735-        Ai[j] -= Ai[k] * Ak[j];
23736-      }
23737-      if(j===n1) Ai[j] -= Ai[k] * Ak[j];
23738-    }
23739-  }
23740-
23741-  return {
23742-    LU: A,
23743-    P:  P
23744-  };
23745-}
23746-
23747-numeric.LUsolve = function LUsolve(LUP, b) {
23748-  var i, j;
23749-  var LU = LUP.LU;
23750-  var n   = LU.length;
23751-  var x = numeric.clone(b);
23752-  var P   = LUP.P;
23753-  var Pi, LUi, LUii, tmp;
23754-
23755-  for (i=n-1;i!==-1;--i) x[i] = b[i];
23756-  for (i = 0; i < n; ++i) {
23757-    Pi = P[i];
23758-    if (P[i] !== i) {
23759-      tmp = x[i];
23760-      x[i] = x[Pi];
23761-      x[Pi] = tmp;
23762-    }
23763-
23764-    LUi = LU[i];
23765-    for (j = 0; j < i; ++j) {
23766-      x[i] -= x[j] * LUi[j];
23767-    }
23768-  }
23769-
23770-  for (i = n - 1; i >= 0; --i) {
23771-    LUi = LU[i];
23772-    for (j = i + 1; j < n; ++j) {
23773-      x[i] -= x[j] * LUi[j];
23774-    }
23775-
23776-    x[i] /= LUi[i];
23777-  }
23778-
23779-  return x;
23780-}
23781-
23782-numeric.solve = function solve(A,b,fast) { return numeric.LUsolve(numeric.LU(A,fast), b); }
23783-
23784-// 12. Linear programming
23785-numeric.echelonize = function echelonize(A) {
23786-  var s = numeric.dim(A), m = s[0], n = s[1];
23787-  var I = numeric.identity(m);
23788-  var P = Array(m);
23789-  var i,j,k,l,Ai,Ii,Z,a;
23790-  var abs = Math.abs;
23791-  var diveq = numeric.diveq;
23792-  A = numeric.clone(A);
23793-  for(i=0;i<m;++i) {
23794-    k = 0;
23795-    Ai = A[i];
23796-    Ii = I[i];
23797-    for(j=1;j<n;++j) if(abs(Ai[k])<abs(Ai[j])) k=j;
23798-    P[i] = k;
23799-    diveq(Ii,Ai[k]);
23800-    diveq(Ai,Ai[k]);
23801-    for(j=0;j<m;++j) if(j!==i) {
23802-      Z = A[j]; a = Z[k];
23803-      for(l=n-1;l!==-1;--l) Z[l] -= Ai[l]*a;
23804-      Z = I[j];
23805-      for(l=m-1;l!==-1;--l) Z[l] -= Ii[l]*a;
23806-    }
23807-  }
23808-  return {I:I, A:A, P:P};
23809-}
23810-
23811-numeric.__solveLP = function __solveLP(c,A,b,tol,maxit,x,flag) {
23812-  var sum = numeric.sum, log = numeric.log, mul = numeric.mul, sub = numeric.sub, dot = numeric.dot, div = numeric.div, add = numeric.add;
23813-  var m = c.length, n = b.length,y;
23814-  var unbounded = false, cb,i0=0;
23815-  var alpha = 1.0;
23816-  var f0,df0,AT = numeric.transpose(A), svd = numeric.svd,transpose = numeric.transpose,leq = numeric.leq, sqrt = Math.sqrt, abs = Math.abs;
23817-  var muleq = numeric.muleq;
23818-  var norm = numeric.norminf, any = numeric.any,min = Math.min;
23819-  var all = numeric.all, gt = numeric.gt;
23820-  var p = Array(m), A0 = Array(n),e=numeric.rep([n],1), H;
23821-  var solve = numeric.solve, z = sub(b,dot(A,x)),count;
23822-  var dotcc = dot(c,c);
23823-  var g;
23824-  for(count=i0;count<maxit;++count) {
23825-    var i,j,d;
23826-    for(i=n-1;i!==-1;--i) A0[i] = div(A[i],z[i]);
23827-    var A1 = transpose(A0);
23828-    for(i=m-1;i!==-1;--i) p[i] = (/*x[i]+*/sum(A1[i]));
23829-    alpha = 0.25*abs(dotcc/dot(c,p));
23830-    var a1 = 100*sqrt(dotcc/dot(p,p));
23831-    if(!isFinite(alpha) || alpha>a1) alpha = a1;
23832-    g = add(c,mul(alpha,p));
23833-    H = dot(A1,A0);
23834-    for(i=m-1;i!==-1;--i) H[i][i] += 1;
23835-    d = solve(H,div(g,alpha),true);
23836-    var t0 = div(z,dot(A,d));
23837-    var t = 1.0;
23838-    for(i=n-1;i!==-1;--i) if(t0[i]<0) t = min(t,-0.999*t0[i]);
23839-    y = sub(x,mul(d,t));
23840-    z = sub(b,dot(A,y));
23841-    if(!all(gt(z,0))) return { solution: x, message: "", iterations: count };
23842-    x = y;
23843-    if(alpha<tol) return { solution: y, message: "", iterations: count };
23844-    if(flag) {
23845-      var s = dot(c,g), Ag = dot(A,g);
23846-      unbounded = true;
23847-      for(i=n-1;i!==-1;--i) if(s*Ag[i]<0) { unbounded = false; break; }
23848-    } else {
23849-      if(x[m-1]>=0) unbounded = false;
23850-      else unbounded = true;
23851-    }
23852-    if(unbounded) return { solution: y, message: "Unbounded", iterations: count };
23853-  }
23854-  return { solution: x, message: "maximum iteration count exceeded", iterations:count };
23855-}
23856-
23857-numeric._solveLP = function _solveLP(c,A,b,tol,maxit) {
23858-  var m = c.length, n = b.length,y;
23859-  var sum = numeric.sum, log = numeric.log, mul = numeric.mul, sub = numeric.sub, dot = numeric.dot, div = numeric.div, add = numeric.add;
23860-  var c0 = numeric.rep([m],0).concat([1]);
23861-  var J = numeric.rep([n,1],-1);
23862-  var A0 = numeric.blockMatrix([[A                   ,   J  ]]);
23863-  var b0 = b;
23864-  var y = numeric.rep([m],0).concat(Math.max(0,numeric.sup(numeric.neg(b)))+1);
23865-  var x0 = numeric.__solveLP(c0,A0,b0,tol,maxit,y,false);
23866-  var x = numeric.clone(x0.solution);
23867-  x.length = m;
23868-  var foo = numeric.inf(sub(b,dot(A,x)));
23869-  if(foo<0) { return { solution: NaN, message: "Infeasible", iterations: x0.iterations }; }
23870-  var ret = numeric.__solveLP(c, A, b, tol, maxit-x0.iterations, x, true);
23871-  ret.iterations += x0.iterations;
23872-  return ret;
23873-};
23874-
23875-numeric.solveLP = function solveLP(c,A,b,Aeq,beq,tol,maxit) {
23876-  if(typeof maxit === "undefined") maxit = 1000;
23877-  if(typeof tol === "undefined") tol = numeric.epsilon;
23878-  if(typeof Aeq === "undefined") return numeric._solveLP(c,A,b,tol,maxit);
23879-  var m = Aeq.length, n = Aeq[0].length, o = A.length;
23880-  var B = numeric.echelonize(Aeq);
23881-  var flags = numeric.rep([n],0);
23882-  var P = B.P;
23883-  var Q = [];
23884-  var i;
23885-  for(i=P.length-1;i!==-1;--i) flags[P[i]] = 1;
23886-  for(i=n-1;i!==-1;--i) if(flags[i]===0) Q.push(i);
23887-  var g = numeric.getRange;
23888-  var I = numeric.linspace(0,m-1), J = numeric.linspace(0,o-1);
23889-  var Aeq2 = g(Aeq,I,Q), A1 = g(A,J,P), A2 = g(A,J,Q), dot = numeric.dot, sub = numeric.sub;
23890-  var A3 = dot(A1,B.I);
23891-  var A4 = sub(A2,dot(A3,Aeq2)), b4 = sub(b,dot(A3,beq));
23892-  var c1 = Array(P.length), c2 = Array(Q.length);
23893-  for(i=P.length-1;i!==-1;--i) c1[i] = c[P[i]];
23894-  for(i=Q.length-1;i!==-1;--i) c2[i] = c[Q[i]];
23895-  var c4 = sub(c2,dot(c1,dot(B.I,Aeq2)));
23896-  var S = numeric._solveLP(c4,A4,b4,tol,maxit);
23897-  var x2 = S.solution;
23898-  if(x2!==x2) return S;
23899-  var x1 = dot(B.I,sub(beq,dot(Aeq2,x2)));
23900-  var x = Array(c.length);
23901-  for(i=P.length-1;i!==-1;--i) x[P[i]] = x1[i];
23902-  for(i=Q.length-1;i!==-1;--i) x[Q[i]] = x2[i];
23903-  return { solution: x, message:S.message, iterations: S.iterations };
23904-}
23905-
23906-numeric.MPStoLP = function MPStoLP(MPS) {
23907-  if(MPS instanceof String) { MPS.split('\n'); }
23908-  var state = 0;
23909-  var states = ['Initial state','NAME','ROWS','COLUMNS','RHS','BOUNDS','ENDATA'];
23910-  var n = MPS.length;
23911-  var i,j,z,N=0,rows = {}, sign = [], rl = 0, vars = {}, nv = 0;
23912-  var name;
23913-  var c = [], A = [], b = [];
23914-  function err(e) { throw new Error('MPStoLP: '+e+'\nLine '+i+': '+MPS[i]+'\nCurrent state: '+states[state]+'\n'); }
23915-  for(i=0;i<n;++i) {
23916-    z = MPS[i];
23917-    var w0 = z.match(/\S*/g);
23918-    var w = [];
23919-    for(j=0;j<w0.length;++j) if(w0[j]!=="") w.push(w0[j]);
23920-    if(w.length === 0) continue;
23921-    for(j=0;j<states.length;++j) if(z.substr(0,states[j].length) === states[j]) break;
23922-    if(j<states.length) {
23923-      state = j;
23924-      if(j===1) { name = w[1]; }
23925-      if(j===6) return { name:name, c:c, A:numeric.transpose(A), b:b, rows:rows, vars:vars };
23926-      continue;
23927-    }
23928-    switch(state) {
23929-      case 0: case 1: err('Unexpected line');
23930-      case 2:
23931-        switch(w[0]) {
23932-          case 'N': if(N===0) N = w[1]; else err('Two or more N rows'); break;
23933-          case 'L': rows[w[1]] = rl; sign[rl] = 1; b[rl] = 0; ++rl; break;
23934-          case 'G': rows[w[1]] = rl; sign[rl] = -1;b[rl] = 0; ++rl; break;
23935-          case 'E': rows[w[1]] = rl; sign[rl] = 0;b[rl] = 0; ++rl; break;
23936-          default: err('Parse error '+numeric.prettyPrint(w));
23937-        }
23938-        break;
23939-      case 3:
23940-        if(!vars.hasOwnProperty(w[0])) { vars[w[0]] = nv; c[nv] = 0; A[nv] = numeric.rep([rl],0); ++nv; }
23941-        var p = vars[w[0]];
23942-        for(j=1;j<w.length;j+=2) {
23943-          if(w[j] === N) { c[p] = parseFloat(w[j+1]); continue; }
23944-          var q = rows[w[j]];
23945-          A[p][q] = (sign[q]<0?-1:1)*parseFloat(w[j+1]);
23946-        }
23947-        break;
23948-      case 4:
23949-        for(j=1;j<w.length;j+=2) b[rows[w[j]]] = (sign[rows[w[j]]]<0?-1:1)*parseFloat(w[j+1]);
23950-        break;
23951-      case 5: /*FIXME*/ break;
23952-      case 6: err('Internal error');
23953-    }
23954-  }
23955-  err('Reached end of file without ENDATA');
23956-}
23957diff --git a/js/parser.js b/lib/parser.js
23958similarity index 99%
23959rename from js/parser.js
23960rename to lib/parser.js
23961index f1f27a2..af9617f 100644
23962--- a/js/parser.js
23963+++ b/lib/parser.js
23964@@ -962,4 +962,8 @@ var Parser = (function(){
23965   }
23966   Parser.prototype = parser;parser.Parser = Parser;
23967   return new Parser;
23968-})();
23969\ No newline at end of file
23970+})();
23971+
23972+module.exports = {
23973+  Parser: Parser
23974+};
23975diff --git a/lib/underscore.string/underscore.string.js b/lib/underscore.string/underscore.string.js
23976deleted file mode 100644
23977index 03af887..0000000
23978--- a/lib/underscore.string/underscore.string.js
23979+++ /dev/null
23980@@ -1,673 +0,0 @@
23981-//  Underscore.string
23982-//  (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
23983-//  Underscore.string is freely distributable under the terms of the MIT license.
23984-//  Documentation: https://github.com/epeli/underscore.string
23985-//  Some code is borrowed from MooTools and Alexandru Marasteanu.
23986-//  Version '2.3.2'
23987-
23988-!function(root, String){
23989-  'use strict';
23990-
23991-  // Defining helper functions.
23992-
23993-  var nativeTrim = String.prototype.trim;
23994-  var nativeTrimRight = String.prototype.trimRight;
23995-  var nativeTrimLeft = String.prototype.trimLeft;
23996-
23997-  var parseNumber = function(source) { return source * 1 || 0; };
23998-
23999-  var strRepeat = function(str, qty){
24000-    if (qty < 1) return '';
24001-    var result = '';
24002-    while (qty > 0) {
24003-      if (qty & 1) result += str;
24004-      qty >>= 1, str += str;
24005-    }
24006-    return result;
24007-  };
24008-
24009-  var slice = [].slice;
24010-
24011-  var defaultToWhiteSpace = function(characters) {
24012-    if (characters == null)
24013-      return '\\s';
24014-    else if (characters.source)
24015-      return characters.source;
24016-    else
24017-      return '[' + _s.escapeRegExp(characters) + ']';
24018-  };
24019-
24020-  // Helper for toBoolean
24021-  function boolMatch(s, matchers) {
24022-    var i, matcher, down = s.toLowerCase();
24023-    matchers = [].concat(matchers);
24024-    for (i = 0; i < matchers.length; i += 1) {
24025-      matcher = matchers[i];
24026-      if (!matcher) continue;
24027-      if (matcher.test && matcher.test(s)) return true;
24028-      if (matcher.toLowerCase() === down) return true;
24029-    }
24030-  }
24031-
24032-  var escapeChars = {
24033-    lt: '<',
24034-    gt: '>',
24035-    quot: '"',
24036-    amp: '&',
24037-    apos: "'"
24038-  };
24039-
24040-  var reversedEscapeChars = {};
24041-  for(var key in escapeChars) reversedEscapeChars[escapeChars[key]] = key;
24042-  reversedEscapeChars["'"] = '#39';
24043-
24044-  // sprintf() for JavaScript 0.7-beta1
24045-  // http://www.diveintojavascript.com/projects/javascript-sprintf
24046-  //
24047-  // Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
24048-  // All rights reserved.
24049-
24050-  var sprintf = (function() {
24051-    function get_type(variable) {
24052-      return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
24053-    }
24054-
24055-    var str_repeat = strRepeat;
24056-
24057-    var str_format = function() {
24058-      if (!str_format.cache.hasOwnProperty(arguments[0])) {
24059-        str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
24060-      }
24061-      return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
24062-    };
24063-
24064-    str_format.format = function(parse_tree, argv) {
24065-      var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
24066-      for (i = 0; i < tree_length; i++) {
24067-        node_type = get_type(parse_tree[i]);
24068-        if (node_type === 'string') {
24069-          output.push(parse_tree[i]);
24070-        }
24071-        else if (node_type === 'array') {
24072-          match = parse_tree[i]; // convenience purposes only
24073-          if (match[2]) { // keyword argument
24074-            arg = argv[cursor];
24075-            for (k = 0; k < match[2].length; k++) {
24076-              if (!arg.hasOwnProperty(match[2][k])) {
24077-                throw new Error(sprintf('[_.sprintf] property "%s" does not exist', match[2][k]));
24078-              }
24079-              arg = arg[match[2][k]];
24080-            }
24081-          } else if (match[1]) { // positional argument (explicit)
24082-            arg = argv[match[1]];
24083-          }
24084-          else { // positional argument (implicit)
24085-            arg = argv[cursor++];
24086-          }
24087-
24088-          if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
24089-            throw new Error(sprintf('[_.sprintf] expecting number but found %s', get_type(arg)));
24090-          }
24091-          switch (match[8]) {
24092-            case 'b': arg = arg.toString(2); break;
24093-            case 'c': arg = String.fromCharCode(arg); break;
24094-            case 'd': arg = parseInt(arg, 10); break;
24095-            case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
24096-            case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
24097-            case 'o': arg = arg.toString(8); break;
24098-            case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
24099-            case 'u': arg = Math.abs(arg); break;
24100-            case 'x': arg = arg.toString(16); break;
24101-            case 'X': arg = arg.toString(16).toUpperCase(); break;
24102-          }
24103-          arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
24104-          pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
24105-          pad_length = match[6] - String(arg).length;
24106-          pad = match[6] ? str_repeat(pad_character, pad_length) : '';
24107-          output.push(match[5] ? arg + pad : pad + arg);
24108-        }
24109-      }
24110-      return output.join('');
24111-    };
24112-
24113-    str_format.cache = {};
24114-
24115-    str_format.parse = function(fmt) {
24116-      var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
24117-      while (_fmt) {
24118-        if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
24119-          parse_tree.push(match[0]);
24120-        }
24121-        else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
24122-          parse_tree.push('%');
24123-        }
24124-        else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
24125-          if (match[2]) {
24126-            arg_names |= 1;
24127-            var field_list = [], replacement_field = match[2], field_match = [];
24128-            if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
24129-              field_list.push(field_match[1]);
24130-              while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
24131-                if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
24132-                  field_list.push(field_match[1]);
24133-                }
24134-                else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
24135-                  field_list.push(field_match[1]);
24136-                }
24137-                else {
24138-                  throw new Error('[_.sprintf] huh?');
24139-                }
24140-              }
24141-            }
24142-            else {
24143-              throw new Error('[_.sprintf] huh?');
24144-            }
24145-            match[2] = field_list;
24146-          }
24147-          else {
24148-            arg_names |= 2;
24149-          }
24150-          if (arg_names === 3) {
24151-            throw new Error('[_.sprintf] mixing positional and named placeholders is not (yet) supported');
24152-          }
24153-          parse_tree.push(match);
24154-        }
24155-        else {
24156-          throw new Error('[_.sprintf] huh?');
24157-        }
24158-        _fmt = _fmt.substring(match[0].length);
24159-      }
24160-      return parse_tree;
24161-    };
24162-
24163-    return str_format;
24164-  })();
24165-
24166-
24167-
24168-  // Defining underscore.string
24169-
24170-  var _s = {
24171-
24172-    VERSION: '2.3.0',
24173-
24174-    isBlank: function(str){
24175-      if (str == null) str = '';
24176-      return (/^\s*$/).test(str);
24177-    },
24178-
24179-    stripTags: function(str){
24180-      if (str == null) return '';
24181-      return String(str).replace(/<\/?[^>]+>/g, '');
24182-    },
24183-
24184-    capitalize : function(str){
24185-      str = str == null ? '' : String(str);
24186-      return str.charAt(0).toUpperCase() + str.slice(1);
24187-    },
24188-
24189-    chop: function(str, step){
24190-      if (str == null) return [];
24191-      str = String(str);
24192-      step = ~~step;
24193-      return step > 0 ? str.match(new RegExp('.{1,' + step + '}', 'g')) : [str];
24194-    },
24195-
24196-    clean: function(str){
24197-      return _s.strip(str).replace(/\s+/g, ' ');
24198-    },
24199-
24200-    count: function(str, substr){
24201-      if (str == null || substr == null) return 0;
24202-
24203-      str = String(str);
24204-      substr = String(substr);
24205-
24206-      var count = 0,
24207-        pos = 0,
24208-        length = substr.length;
24209-
24210-      while (true) {
24211-        pos = str.indexOf(substr, pos);
24212-        if (pos === -1) break;
24213-        count++;
24214-        pos += length;
24215-      }
24216-
24217-      return count;
24218-    },
24219-
24220-    chars: function(str) {
24221-      if (str == null) return [];
24222-      return String(str).split('');
24223-    },
24224-
24225-    swapCase: function(str) {
24226-      if (str == null) return '';
24227-      return String(str).replace(/\S/g, function(c){
24228-        return c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase();
24229-      });
24230-    },
24231-
24232-    escapeHTML: function(str) {
24233-      if (str == null) return '';
24234-      return String(str).replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; });
24235-    },
24236-
24237-    unescapeHTML: function(str) {
24238-      if (str == null) return '';
24239-      return String(str).replace(/\&([^;]+);/g, function(entity, entityCode){
24240-        var match;
24241-
24242-        if (entityCode in escapeChars) {
24243-          return escapeChars[entityCode];
24244-        } else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
24245-          return String.fromCharCode(parseInt(match[1], 16));
24246-        } else if (match = entityCode.match(/^#(\d+)$/)) {
24247-          return String.fromCharCode(~~match[1]);
24248-        } else {
24249-          return entity;
24250-        }
24251-      });
24252-    },
24253-
24254-    escapeRegExp: function(str){
24255-      if (str == null) return '';
24256-      return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
24257-    },
24258-
24259-    splice: function(str, i, howmany, substr){
24260-      var arr = _s.chars(str);
24261-      arr.splice(~~i, ~~howmany, substr);
24262-      return arr.join('');
24263-    },
24264-
24265-    insert: function(str, i, substr){
24266-      return _s.splice(str, i, 0, substr);
24267-    },
24268-
24269-    include: function(str, needle){
24270-      if (needle === '') return true;
24271-      if (str == null) return false;
24272-      return String(str).indexOf(needle) !== -1;
24273-    },
24274-
24275-    join: function() {
24276-      var args = slice.call(arguments),
24277-        separator = args.shift();
24278-
24279-      if (separator == null) separator = '';
24280-
24281-      return args.join(separator);
24282-    },
24283-
24284-    lines: function(str) {
24285-      if (str == null) return [];
24286-      return String(str).split("\n");
24287-    },
24288-
24289-    reverse: function(str){
24290-      return _s.chars(str).reverse().join('');
24291-    },
24292-
24293-    startsWith: function(str, starts){
24294-      if (starts === '') return true;
24295-      if (str == null || starts == null) return false;
24296-      str = String(str); starts = String(starts);
24297-      return str.length >= starts.length && str.slice(0, starts.length) === starts;
24298-    },
24299-
24300-    endsWith: function(str, ends){
24301-      if (ends === '') return true;
24302-      if (str == null || ends == null) return false;
24303-      str = String(str); ends = String(ends);
24304-      return str.length >= ends.length && str.slice(str.length - ends.length) === ends;
24305-    },
24306-
24307-    succ: function(str){
24308-      if (str == null) return '';
24309-      str = String(str);
24310-      return str.slice(0, -1) + String.fromCharCode(str.charCodeAt(str.length-1) + 1);
24311-    },
24312-
24313-    titleize: function(str){
24314-      if (str == null) return '';
24315-      str  = String(str).toLowerCase();
24316-      return str.replace(/(?:^|\s|-)\S/g, function(c){ return c.toUpperCase(); });
24317-    },
24318-
24319-    camelize: function(str){
24320-      return _s.trim(str).replace(/[-_\s]+(.)?/g, function(match, c){ return c ? c.toUpperCase() : ""; });
24321-    },
24322-
24323-    underscored: function(str){
24324-      return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
24325-    },
24326-
24327-    dasherize: function(str){
24328-      return _s.trim(str).replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
24329-    },
24330-
24331-    classify: function(str){
24332-      return _s.titleize(String(str).replace(/[\W_]/g, ' ')).replace(/\s/g, '');
24333-    },
24334-
24335-    humanize: function(str){
24336-      return _s.capitalize(_s.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
24337-    },
24338-
24339-    trim: function(str, characters){
24340-      if (str == null) return '';
24341-      if (!characters && nativeTrim) return nativeTrim.call(str);
24342-      characters = defaultToWhiteSpace(characters);
24343-      return String(str).replace(new RegExp('\^' + characters + '+|' + characters + '+$', 'g'), '');
24344-    },
24345-
24346-    ltrim: function(str, characters){
24347-      if (str == null) return '';
24348-      if (!characters && nativeTrimLeft) return nativeTrimLeft.call(str);
24349-      characters = defaultToWhiteSpace(characters);
24350-      return String(str).replace(new RegExp('^' + characters + '+'), '');
24351-    },
24352-
24353-    rtrim: function(str, characters){
24354-      if (str == null) return '';
24355-      if (!characters && nativeTrimRight) return nativeTrimRight.call(str);
24356-      characters = defaultToWhiteSpace(characters);
24357-      return String(str).replace(new RegExp(characters + '+$'), '');
24358-    },
24359-
24360-    truncate: function(str, length, truncateStr){
24361-      if (str == null) return '';
24362-      str = String(str); truncateStr = truncateStr || '...';
24363-      length = ~~length;
24364-      return str.length > length ? str.slice(0, length) + truncateStr : str;
24365-    },
24366-
24367-    /**
24368-     * _s.prune: a more elegant version of truncate
24369-     * prune extra chars, never leaving a half-chopped word.
24370-     * @author github.com/rwz
24371-     */
24372-    prune: function(str, length, pruneStr){
24373-      if (str == null) return '';
24374-
24375-      str = String(str); length = ~~length;
24376-      pruneStr = pruneStr != null ? String(pruneStr) : '...';
24377-
24378-      if (str.length <= length) return str;
24379-
24380-      var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; },
24381-        template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'
24382-
24383-      if (template.slice(template.length-2).match(/\w\w/))
24384-        template = template.replace(/\s*\S+$/, '');
24385-      else
24386-        template = _s.rtrim(template.slice(0, template.length-1));
24387-
24388-      return (template+pruneStr).length > str.length ? str : str.slice(0, template.length)+pruneStr;
24389-    },
24390-
24391-    words: function(str, delimiter) {
24392-      if (_s.isBlank(str)) return [];
24393-      return _s.trim(str, delimiter).split(delimiter || /\s+/);
24394-    },
24395-
24396-    pad: function(str, length, padStr, type) {
24397-      str = str == null ? '' : String(str);
24398-      length = ~~length;
24399-
24400-      var padlen  = 0;
24401-
24402-      if (!padStr)
24403-        padStr = ' ';
24404-      else if (padStr.length > 1)
24405-        padStr = padStr.charAt(0);
24406-
24407-      switch(type) {
24408-        case 'right':
24409-          padlen = length - str.length;
24410-          return str + strRepeat(padStr, padlen);
24411-        case 'both':
24412-          padlen = length - str.length;
24413-          return strRepeat(padStr, Math.ceil(padlen/2)) + str
24414-            + strRepeat(padStr, Math.floor(padlen/2));
24415-        default: // 'left'
24416-          padlen = length - str.length;
24417-          return strRepeat(padStr, padlen) + str;
24418-      }
24419-    },
24420-
24421-    lpad: function(str, length, padStr) {
24422-      return _s.pad(str, length, padStr);
24423-    },
24424-
24425-    rpad: function(str, length, padStr) {
24426-      return _s.pad(str, length, padStr, 'right');
24427-    },
24428-
24429-    lrpad: function(str, length, padStr) {
24430-      return _s.pad(str, length, padStr, 'both');
24431-    },
24432-
24433-    sprintf: sprintf,
24434-
24435-    vsprintf: function(fmt, argv){
24436-      argv.unshift(fmt);
24437-      return sprintf.apply(null, argv);
24438-    },
24439-
24440-    toNumber: function(str, decimals) {
24441-      if (!str) return 0;
24442-      str = _s.trim(str);
24443-      if (!str.match(/^-?\d+(?:\.\d+)?$/)) return NaN;
24444-      return parseNumber(parseNumber(str).toFixed(~~decimals));
24445-    },
24446-
24447-    numberFormat : function(number, dec, dsep, tsep) {
24448-      if (isNaN(number) || number == null) return '';
24449-
24450-      number = number.toFixed(~~dec);
24451-      tsep = typeof tsep == 'string' ? tsep : ',';
24452-
24453-      var parts = number.split('.'), fnums = parts[0],
24454-        decimals = parts[1] ? (dsep || '.') + parts[1] : '';
24455-
24456-      return fnums.replace(/(\d)(?=(?:\d{3})+$)/g, '$1' + tsep) + decimals;
24457-    },
24458-
24459-    strRight: function(str, sep){
24460-      if (str == null) return '';
24461-      str = String(str); sep = sep != null ? String(sep) : sep;
24462-      var pos = !sep ? -1 : str.indexOf(sep);
24463-      return ~pos ? str.slice(pos+sep.length, str.length) : str;
24464-    },
24465-
24466-    strRightBack: function(str, sep){
24467-      if (str == null) return '';
24468-      str = String(str); sep = sep != null ? String(sep) : sep;
24469-      var pos = !sep ? -1 : str.lastIndexOf(sep);
24470-      return ~pos ? str.slice(pos+sep.length, str.length) : str;
24471-    },
24472-
24473-    strLeft: function(str, sep){
24474-      if (str == null) return '';
24475-      str = String(str); sep = sep != null ? String(sep) : sep;
24476-      var pos = !sep ? -1 : str.indexOf(sep);
24477-      return ~pos ? str.slice(0, pos) : str;
24478-    },
24479-
24480-    strLeftBack: function(str, sep){
24481-      if (str == null) return '';
24482-      str += ''; sep = sep != null ? ''+sep : sep;
24483-      var pos = str.lastIndexOf(sep);
24484-      return ~pos ? str.slice(0, pos) : str;
24485-    },
24486-
24487-    toSentence: function(array, separator, lastSeparator, serial) {
24488-      separator = separator || ', ';
24489-      lastSeparator = lastSeparator || ' and ';
24490-      var a = array.slice(), lastMember = a.pop();
24491-
24492-      if (array.length > 2 && serial) lastSeparator = _s.rtrim(separator) + lastSeparator;
24493-
24494-      return a.length ? a.join(separator) + lastSeparator + lastMember : lastMember;
24495-    },
24496-
24497-    toSentenceSerial: function() {
24498-      var args = slice.call(arguments);
24499-      args[3] = true;
24500-      return _s.toSentence.apply(_s, args);
24501-    },
24502-
24503-    slugify: function(str) {
24504-      if (str == null) return '';
24505-
24506-      var from  = "ąàáäâãåæăćęèéëêìíïîłńòóöôõøśșțùúüûñçżź",
24507-        to    = "aaaaaaaaaceeeeeiiiilnoooooosstuuuunczz",
24508-        regex = new RegExp(defaultToWhiteSpace(from), 'g');
24509-
24510-      str = String(str).toLowerCase().replace(regex, function(c){
24511-        var index = from.indexOf(c);
24512-        return to.charAt(index) || '-';
24513-      });
24514-
24515-      return _s.dasherize(str.replace(/[^\w\s-]/g, ''));
24516-    },
24517-
24518-    surround: function(str, wrapper) {
24519-      return [wrapper, str, wrapper].join('');
24520-    },
24521-
24522-    quote: function(str, quoteChar) {
24523-      return _s.surround(str, quoteChar || '"');
24524-    },
24525-
24526-    unquote: function(str, quoteChar) {
24527-      quoteChar = quoteChar || '"';
24528-      if (str[0] === quoteChar && str[str.length-1] === quoteChar)
24529-        return str.slice(1,str.length-1);
24530-      else return str;
24531-    },
24532-
24533-    exports: function() {
24534-      var result = {};
24535-
24536-      for (var prop in this) {
24537-        if (!this.hasOwnProperty(prop) || prop.match(/^(?:include|contains|reverse)$/)) continue;
24538-        result[prop] = this[prop];
24539-      }
24540-
24541-      return result;
24542-    },
24543-
24544-    repeat: function(str, qty, separator){
24545-      if (str == null) return '';
24546-
24547-      qty = ~~qty;
24548-
24549-      // using faster implementation if separator is not needed;
24550-      if (separator == null) return strRepeat(String(str), qty);
24551-
24552-      // this one is about 300x slower in Google Chrome
24553-      for (var repeat = []; qty > 0; repeat[--qty] = str) {}
24554-      return repeat.join(separator);
24555-    },
24556-
24557-    naturalCmp: function(str1, str2){
24558-      if (str1 == str2) return 0;
24559-      if (!str1) return -1;
24560-      if (!str2) return 1;
24561-
24562-      var cmpRegex = /(\.\d+)|(\d+)|(\D+)/g,
24563-        tokens1 = String(str1).toLowerCase().match(cmpRegex),
24564-        tokens2 = String(str2).toLowerCase().match(cmpRegex),
24565-        count = Math.min(tokens1.length, tokens2.length);
24566-
24567-      for(var i = 0; i < count; i++) {
24568-        var a = tokens1[i], b = tokens2[i];
24569-
24570-        if (a !== b){
24571-          var num1 = parseInt(a, 10);
24572-          if (!isNaN(num1)){
24573-            var num2 = parseInt(b, 10);
24574-            if (!isNaN(num2) && num1 - num2)
24575-              return num1 - num2;
24576-          }
24577-          return a < b ? -1 : 1;
24578-        }
24579-      }
24580-
24581-      if (tokens1.length === tokens2.length)
24582-        return tokens1.length - tokens2.length;
24583-
24584-      return str1 < str2 ? -1 : 1;
24585-    },
24586-
24587-    levenshtein: function(str1, str2) {
24588-      if (str1 == null && str2 == null) return 0;
24589-      if (str1 == null) return String(str2).length;
24590-      if (str2 == null) return String(str1).length;
24591-
24592-      str1 = String(str1); str2 = String(str2);
24593-
24594-      var current = [], prev, value;
24595-
24596-      for (var i = 0; i <= str2.length; i++)
24597-        for (var j = 0; j <= str1.length; j++) {
24598-          if (i && j)
24599-            if (str1.charAt(j - 1) === str2.charAt(i - 1))
24600-              value = prev;
24601-            else
24602-              value = Math.min(current[j], current[j - 1], prev) + 1;
24603-          else
24604-            value = i + j;
24605-
24606-          prev = current[j];
24607-          current[j] = value;
24608-        }
24609-
24610-      return current.pop();
24611-    },
24612-
24613-    toBoolean: function(str, trueValues, falseValues) {
24614-      if (typeof str === "number") str = "" + str;
24615-      if (typeof str !== "string") return !!str;
24616-      str = _s.trim(str);
24617-      if (boolMatch(str, trueValues || ["true", "1"])) return true;
24618-      if (boolMatch(str, falseValues || ["false", "0"])) return false;
24619-    }
24620-  };
24621-
24622-  // Aliases
24623-
24624-  _s.strip    = _s.trim;
24625-  _s.lstrip   = _s.ltrim;
24626-  _s.rstrip   = _s.rtrim;
24627-  _s.center   = _s.lrpad;
24628-  _s.rjust    = _s.lpad;
24629-  _s.ljust    = _s.rpad;
24630-  _s.contains = _s.include;
24631-  _s.q        = _s.quote;
24632-  _s.toBool   = _s.toBoolean;
24633-
24634-  // Exporting
24635-
24636-  // CommonJS module is defined
24637-  if (typeof exports !== 'undefined') {
24638-    if (typeof module !== 'undefined' && module.exports)
24639-      module.exports = _s;
24640-
24641-    exports._s = _s;
24642-  }
24643-
24644-  // Register as a named module with AMD.
24645-  if (typeof define === 'function' && define.amd)
24646-    define('underscore.string', [], function(){ return _s; });
24647-
24648-
24649-  // Integrate with Underscore.js if defined
24650-  // or create our own underscore object.
24651-  root._ = root._ || {};
24652-  root._.string = root._.str = _s;
24653-}(this, String);
24654diff --git a/mine.html b/mine.html
24655deleted file mode 100644
24656index 3fab627..0000000
24657--- a/mine.html
24658+++ /dev/null
24659@@ -1,158 +0,0 @@
24660-<!doctype html>
24661-<html>
24662-<head>
24663-  <meta charset='utf-8'>
24664-  <title>Mine</title>
24665-
24666-  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
24667-
24668-  <script src="lib/lodash/lodash.js"></script>
24669-  <script src="lib/underscore.string/underscore.string.js"></script>
24670-  <script src="lib/moment/moment.js"></script>
24671-  <script src="lib/numeral/numeral.js"></script>
24672-  <script src="lib/numericjs/numeric.js"></script>
24673-  <script src="lib/js-md5/md5.js"></script>
24674-  <script src="lib/jstat/jstat.js"></script>
24675-  <script src="lib/formulajs/formula.js"></script>
24676-
24677-  <script src="js/parser.js"></script>
24678-  <script src="js/mine.js"></script>
24679-  <script src="js/ruleJS.js"></script>
24680-  <style>
24681-    .table input[type=text] {
24682-      width: 50px;
24683-    }
24684-    #suportedList ul {
24685-      -webkit-column-count: 4; -webkit-column-gap:20px;
24686-      -moz-column-count:4; -moz-column-gap:20px;
24687-      -o-column-count:4; -o-column-gap:20px;
24688-      column-count:4; column-gap:20px;
24689-    }
24690-  </style>
24691-</head>
24692-<body>
24693-<div class="col-xs-12">
24694-  <section>
24695-    <h1 class="page-header">RuleJS</h1>
24696-    <section>
24697-      <h1 class="page-header">Demo</h1>
24698-      <p>Try to parse the formula by typing ex. <code>AND(1,0)</code> into input below and press <kbd>Parse</kbd> button.</p>
24699-
24700-      <div class="col-xs-12" style="padding: 0px;" id="mine">
24701-
24702-        <input type="text" id="X1" placeholder="ex. AND(1,0)"><button>Parse</button>
24703-
24704-        <p class="bg-info" style="display: none">result: <span id="result"></span></p>
24705-        <p class="bg-danger" style="display: none">error: <span id="error"></span></p>
24706-        <p class="clearfix"></p>
24707-
24708-        <p>Try to insert formula into input field by typing ex. <code>=A1</code>. It's possible to edit formula by double clicked on input field.</p>
24709-        <table class="table table-bordered">
24710-          <thead>
24711-          <tr>
24712-            <td></td>
24713-            <td>A</td>
24714-            <td>B</td>
24715-            <td>C</td>
24716-            <td>D</td>
24717-            <td>E</td>
24718-            <td>F</td>
24719-            <td>G</td>
24720-            <td>H</td>
24721-            <td>I</td>
24722-            <td>J</td>
24723-            <td colspan="2" class="text-center">fn(x)</td>
24724-          </tr>
24725-          </thead>
24726-          <tbody>
24727-          <tr>
24728-            <td>1</td>
24729-            <td><input type="text" id="A1" value="1"></td>
24730-            <td><input type="text" id="B1" value="2"></td>
24731-            <td><input type="text" id="C1" value="3"></td>
24732-            <td><input type="text" id="D1" value="4"></td>
24733-            <td><input type="text" id="E1" value="5"></td>
24734-            <td><input type="text" id="F1" value="6"></td>
24735-            <td><input type="text" id="G1" value="7"></td>
24736-            <td><input type="text" id="H1" value="8"></td>
24737-            <td><input type="text" id="I1" value="9"></td>
24738-            <td><input type="text" id="J1" value="10"></td>
24739-            <td>SUM(A1:D1, H1)</td>
24740-            <td><span id="K1" data-formula="SUM(A1:D1, H1)"></span></td>
24741-          </tr>
24742-          <tr>
24743-            <td>2</td>
24744-            <td><input type="text" id="A2" value="-1"></td>
24745-            <td><input type="text" id="B2" value="-10"></td>
24746-            <td><input type="text" id="C2" value="2"></td>
24747-            <td><input type="text" id="D2" value="4"></td>
24748-            <td><input type="text" id="E2" value="100"></td>
24749-            <td><input type="text" id="F2" value="1"></td>
24750-            <td><input type="text" id="G2" value="50"></td>
24751-            <td><input type="text" id="H2" value="20"></td>
24752-            <td><input type="text" id="I2" value="200"></td>
24753-            <td><input type="text" id="J2" value="-100"></td>
24754-            <td>MAX(A2:J2)</td>
24755-            <td><span id="K2" data-formula="MAX(A2:J2)"></span></td>
24756-          </tr>
24757-          <tr>
24758-            <td>3</td>
24759-            <td><input type="text" id="A3" value="-1"></td>
24760-            <td><input type="text" id="B3" value="-40"></td>
24761-            <td><input type="text" id="C3" value="-53"></td>
24762-            <td><input type="text" id="D3" value="1"></td>
24763-            <td><input type="text" id="E3" value="10"></td>
24764-            <td><input type="text" id="F3" value="30"></td>
24765-            <td><input type="text" id="G3" value="10"></td>
24766-            <td><input type="text" id="H3" value="301"></td>
24767-            <td><input type="text" id="I3" value="-1"></td>
24768-            <td><input type="text" id="J3" value="-20"></td>
24769-            <td>MIN(A3:J3)</td>
24770-            <td><span id="K3" data-formula="MIN(A3:J3)"></span></td>
24771-          </tr>
24772-          <tr>
24773-            <td>4</td>
24774-            <td><input type="text" id="A4" value="20"></td>
24775-            <td><input type="text" id="B4" value="50"></td>
24776-            <td><input type="text" id="C4" value="100"></td>
24777-            <td><input type="text" id="D4" value="20"></td>
24778-            <td><input type="text" id="E4" value="1"></td>
24779-            <td><input type="text" id="F4" value="5"></td>
24780-            <td><input type="text" id="G4" value="15"></td>
24781-            <td><input type="text" id="H4" value="25"></td>
24782-            <td><input type="text" id="I4" value="45"></td>
24783-            <td><input type="text" id="J4" value="23"></td>
24784-            <td>AVERAGE(A4:J4):</td>
24785-            <td><span id="K4" data-formula="AVERAGE(A4:J4)"></span></td>
24786-          </tr>
24787-          <tr>
24788-            <td>5</td>
24789-            <td><input type="text" id="A5" value="0"></td>
24790-            <td><input type="text" id="B5" value="10"></td>
24791-            <td><input type="text" id="C5" value="1"></td>
24792-            <td><input type="text" id="D5" value="10"></td>
24793-            <td><input type="text" id="E5" value="2"></td>
24794-            <td><input type="text" id="F5" value="10"></td>
24795-            <td><input type="text" id="G5" value="3"></td>
24796-            <td><input type="text" id="H5" value="10"></td>
24797-            <td><input type="text" id="I5" value="4"></td>
24798-            <td><input type="text" id="J5" value="10"></td>
24799-            <td>SUMIF(A5:J5,'>5')</td>
24800-            <td><span id="K5" data-formula="SUMIF(A5:J5,'>5')"></span></td>
24801-          </tr>
24802-          </tbody>
24803-        </table>
24804-      </div>
24805-
24806-
24807-
24808-    </section>
24809-  </section>
24810-</div>
24811-
24812-<script>
24813-  var m = new mine('mine');
24814-  m.init();
24815-</script>
24816-</body>
24817-</html>
24818diff --git a/package.json b/package.json
24819new file mode 100644
24820index 0000000..c7f0c48
24821--- /dev/null
24822+++ b/package.json
24823@@ -0,0 +1,13 @@
24824+{
24825+  "name": "spreadsheet",
24826+  "version": "1.0.0",
24827+  "description": "TypeScript implementation of a spreadsheet.",
24828+  "scripts": {
24829+    "build": "tsc && cp lib/parser.js output/"
24830+  },
24831+  "author": "vogtb <bvogt at gmail.com>",
24832+  "license": "MIT",
24833+  "dependencies": {
24834+    "formulajs": "^1.0.8"
24835+  }
24836+}
24837diff --git a/rule.html b/rule.html
24838deleted file mode 100644
24839index 0ad587f..0000000
24840--- a/rule.html
24841+++ /dev/null
24842@@ -1,161 +0,0 @@
24843-<!doctype html>
24844-<html>
24845-<head>
24846-  <meta charset='utf-8'>
24847-  <title>RuleJS</title>
24848-
24849-  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
24850-
24851-  <script src="lib/lodash/lodash.js"></script>
24852-  <script src="lib/underscore.string/underscore.string.js"></script>
24853-  <script src="lib/moment/moment.js"></script>
24854-  <script src="lib/numeral/numeral.js"></script>
24855-  <script src="lib/numericjs/numeric.js"></script>
24856-  <script src="lib/js-md5/md5.js"></script>
24857-  <script src="lib/jstat/jstat.js"></script>
24858-  <script src="lib/formulajs/formula.js"></script>
24859-
24860-  <script src="js/parser.js"></script>
24861-  <script src="js/mine.js"></script>
24862-  <script src="js/ruleJS.js"></script>
24863-  <style>
24864-    .table input[type=text] {
24865-      width: 50px;
24866-    }
24867-    #suportedList ul {
24868-      -webkit-column-count: 4; -webkit-column-gap:20px;
24869-      -moz-column-count:4; -moz-column-gap:20px;
24870-      -o-column-count:4; -o-column-gap:20px;
24871-      column-count:4; column-gap:20px;
24872-    }
24873-  </style>
24874-</head>
24875-<body>
24876-<div class="col-xs-12">
24877-  <section>
24878-    <h1 class="page-header">RuleJS</h1>
24879-  <section>
24880-    <h1 class="page-header">Demo</h1>
24881-    <p>Try to parse the formula by typing ex. <code>AND(1,0)</code> into input below and press <kbd>Parse</kbd> button.</p>
24882-
24883-    <div class="col-xs-12" style="padding: 0px;" id="demo1">
24884-
24885-      <input type="text" id="X1" placeholder="ex. AND(1,0)"><button>Parse</button>
24886-
24887-      <p class="bg-info" style="display: none">result: <span id="result"></span></p>
24888-      <p class="bg-danger" style="display: none">error: <span id="error"></span></p>
24889-      <p class="clearfix"></p>
24890-
24891-      <p>Try to insert formula into input field by typing ex. <code>=A1</code>. It's possible to edit formula by double clicked on input field.</p>
24892-      <table class="table table-bordered">
24893-        <thead>
24894-        <tr>
24895-          <td></td>
24896-          <td>A</td>
24897-          <td>B</td>
24898-          <td>C</td>
24899-          <td>D</td>
24900-          <td>E</td>
24901-          <td>F</td>
24902-          <td>G</td>
24903-          <td>H</td>
24904-          <td>I</td>
24905-          <td>J</td>
24906-          <td colspan="2" class="text-center">fn(x)</td>
24907-        </tr>
24908-        </thead>
24909-        <tbody>
24910-        <tr>
24911-          <td>1</td>
24912-          <td><input type="text" id="A1" value="1"></td>
24913-          <td><input type="text" id="B1" value="2"></td>
24914-          <td><input type="text" id="C1" value="3"></td>
24915-          <td><input type="text" id="D1" value="4"></td>
24916-          <td><input type="text" id="E1" value="5"></td>
24917-          <td><input type="text" id="F1" value="6"></td>
24918-          <td><input type="text" id="G1" value="7"></td>
24919-          <td><input type="text" id="H1" value="8"></td>
24920-          <td><input type="text" id="I1" value="9"></td>
24921-          <td><input type="text" id="J1" value="10"></td>
24922-          <td>SUM(A1:D1, H1)</td>
24923-          <td><span id="K1" data-formula="SUM(A1:D1, H1)"></span></td>
24924-        </tr>
24925-        <tr>
24926-          <td>2</td>
24927-          <td><input type="text" id="A2" value="-1"></td>
24928-          <td><input type="text" id="B2" value="-10"></td>
24929-          <td><input type="text" id="C2" value="2"></td>
24930-          <td><input type="text" id="D2" value="4"></td>
24931-          <td><input type="text" id="E2" value="100"></td>
24932-          <td><input type="text" id="F2" value="1"></td>
24933-          <td><input type="text" id="G2" value="50"></td>
24934-          <td><input type="text" id="H2" value="20"></td>
24935-          <td><input type="text" id="I2" value="200"></td>
24936-          <td><input type="text" id="J2" value="-100"></td>
24937-          <td>MAX(A2:J2)</td>
24938-          <td><span id="K2" data-formula="MAX(A2:J2)"></span></td>
24939-        </tr>
24940-        <tr>
24941-          <td>3</td>
24942-          <td><input type="text" id="A3" value="-1"></td>
24943-          <td><input type="text" id="B3" value="-40"></td>
24944-          <td><input type="text" id="C3" value="-53"></td>
24945-          <td><input type="text" id="D3" value="1"></td>
24946-          <td><input type="text" id="E3" value="10"></td>
24947-          <td><input type="text" id="F3" value="30"></td>
24948-          <td><input type="text" id="G3" value="10"></td>
24949-          <td><input type="text" id="H3" value="301"></td>
24950-          <td><input type="text" id="I3" value="-1"></td>
24951-          <td><input type="text" id="J3" value="-20"></td>
24952-          <td>MIN(A3:J3)</td>
24953-          <td><span id="K3" data-formula="MIN(A3:J3)"></span></td>
24954-        </tr>
24955-        <tr>
24956-          <td>4</td>
24957-          <td><input type="text" id="A4" value="20"></td>
24958-          <td><input type="text" id="B4" value="50"></td>
24959-          <td><input type="text" id="C4" value="100"></td>
24960-          <td><input type="text" id="D4" value="20"></td>
24961-          <td><input type="text" id="E4" value="1"></td>
24962-          <td><input type="text" id="F4" value="5"></td>
24963-          <td><input type="text" id="G4" value="15"></td>
24964-          <td><input type="text" id="H4" value="25"></td>
24965-          <td><input type="text" id="I4" value="45"></td>
24966-          <td><input type="text" id="J4" value="23"></td>
24967-          <td>AVERAGE(A4:J4):</td>
24968-          <td><span id="K4" data-formula="AVERAGE(A4:J4)"></span></td>
24969-        </tr>
24970-        <tr>
24971-          <td>5</td>
24972-          <td><input type="text" id="A5" value="0"></td>
24973-          <td><input type="text" id="B5" value="10"></td>
24974-          <td><input type="text" id="C5" value="1"></td>
24975-          <td><input type="text" id="D5" value="10"></td>
24976-          <td><input type="text" id="E5" value="2"></td>
24977-          <td><input type="text" id="F5" value="10"></td>
24978-          <td><input type="text" id="G5" value="3"></td>
24979-          <td><input type="text" id="H5" value="10"></td>
24980-          <td><input type="text" id="I5" value="4"></td>
24981-          <td><input type="text" id="J5" value="10"></td>
24982-          <td>SUMIF(A5:J5,'>5')</td>
24983-          <td><span id="K5" data-formula="SUMIF(A5:J5,'>5')"></span></td>
24984-        </tr>
24985-        </tbody>
24986-      </table>
24987-    </div>
24988-
24989-  </section>
24990-  </section>
24991-
24992-</div>
24993-
24994-<script>
24995-  (function () {
24996-
24997-    var rules = new ruleJS('demo1');
24998-    rules.init();
24999-
25000-  })();
25001-</script>
25002-</body>
25003-</html>
25004diff --git a/ts.html b/ts.html
25005deleted file mode 100644
25006index dcded9d..0000000
25007--- a/ts.html
25008+++ /dev/null
25009@@ -1,26 +0,0 @@
25010-<!doctype html>
25011-<html>
25012-<head>
25013-  <meta charset='utf-8'>
25014-  <title>TS</title>
25015-
25016-  <script src="lib/lodash/lodash.js"></script>
25017-  <script src="lib/underscore.string/underscore.string.js"></script>
25018-  <script src="lib/moment/moment.js"></script>
25019-  <script src="lib/numeral/numeral.js"></script>
25020-  <script src="lib/numericjs/numeric.js"></script>
25021-  <script src="lib/js-md5/md5.js"></script>
25022-  <script src="lib/jstat/jstat.js"></script>
25023-  <script src="lib/formulajs/formula.js"></script>
25024-
25025-  <script src="ts/parser.js"></script>
25026-  <script src="ts/sheet.js"></script>
25027-</head>
25028-<body>
25029-look at the console.
25030-<script>
25031-  var sheet = new Sheet();
25032-  sheet.init();
25033-</script>
25034-</body>
25035-</html>
25036diff --git a/ts/Main.ts b/ts/Main.ts
25037new file mode 100644
25038index 0000000..0633f2b
25039--- /dev/null
25040+++ b/ts/Main.ts
25041@@ -0,0 +1,4 @@
25042+import { Sheet } from "./Sheet"
25043+
25044+var sheet = Sheet();
25045+sheet.init();
25046\ No newline at end of file
25047diff --git a/ts/Parser.d.ts b/ts/Parser.d.ts
25048new file mode 100644
25049index 0000000..ebf4c90
25050--- /dev/null
25051+++ b/ts/Parser.d.ts
25052@@ -0,0 +1,12 @@
25053+interface P {
25054+  yy: any;
25055+  lexer: any;
25056+  parse: any;
25057+  parseError: any;
25058+}
25059+
25060+declare var Parser: P;
25061+
25062+export {
25063+  Parser
25064+}
25065\ No newline at end of file
25066diff --git a/ts/sheet.ts b/ts/Sheet.ts
25067similarity index 99%
25068rename from ts/sheet.ts
25069rename to ts/Sheet.ts
25070index 5228401..57607ff 100644
25071--- a/ts/sheet.ts
25072+++ b/ts/Sheet.ts
25073@@ -1,20 +1,7 @@
25074-interface P {
25075-  yy: any;
25076-  lexer: any;
25077-  parse: any;
25078-  parseError: any;
25079-}
25080-
25081-declare var Parser: P;
25082-declare var Formula: any;
25083-
25084-
25085-
25086-
25087-
25088-
25089-
25090+/// <reference path="parser.d.ts"/>
25091+import { Parser } from "./Parser";
25092 
25093+import * as Formula from "formulajs"
25094 
25095 /**
25096  * A1-notation style cell id. Used to index the cells.
25097@@ -63,8 +50,6 @@ function numberToLetters(num: number): string {
25098 }
25099 
25100 
25101-
25102-
25103 class Cell {
25104   public formula: string;
25105   public value: string;
25106@@ -702,3 +687,7 @@ var Sheet = (function () {
25107   };
25108 
25109 });
25110+
25111+export {
25112+  Sheet
25113+}
25114\ No newline at end of file
25115diff --git a/ts/parser.js b/ts/parser.js
25116deleted file mode 100644
25117index f1f27a2..0000000
25118--- a/ts/parser.js
25119+++ /dev/null
25120@@ -1,965 +0,0 @@
25121-/* parser generated by jison 0.4.15 */
25122-/*
25123- Returns a Parser object of the following structure:
25124-
25125- Parser: {
25126- yy: {}
25127- }
25128-
25129- Parser.prototype: {
25130- yy: {},
25131- trace: function(),
25132- symbols_: {associative list: name ==> number},
25133- terminals_: {associative list: number ==> name},
25134- productions_: [...],
25135- performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
25136- table: [...],
25137- defaultActions: {...},
25138- parseError: function(str, hash),
25139- parse: function(input),
25140-
25141- lexer: {
25142- EOF: 1,
25143- parseError: function(str, hash),
25144- setInput: function(input),
25145- input: function(),
25146- unput: function(str),
25147- more: function(),
25148- less: function(n),
25149- pastInput: function(),
25150- upcomingInput: function(),
25151- showPosition: function(),
25152- test_match: function(regex_match_array, rule_index),
25153- next: function(),
25154- lex: function(),
25155- begin: function(condition),
25156- popState: function(),
25157- _currentRules: function(),
25158- topState: function(),
25159- pushState: function(condition),
25160-
25161- options: {
25162- ranges: boolean           (optional: true ==> token location info will include a .range[] member)
25163- flex: boolean             (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
25164- backtrack_lexer: boolean  (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
25165- },
25166-
25167- performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
25168- rules: [...],
25169- conditions: {associative list: name ==> set},
25170- }
25171- }
25172-
25173-
25174- token location info (@$, _$, etc.): {
25175- first_line: n,
25176- last_line: n,
25177- first_column: n,
25178- last_column: n,
25179- range: [start_number, end_number]       (where the numbers are indexes into the input string, regular zero-based)
25180- }
25181-
25182-
25183- the parseError function receives a 'hash' object with these members for lexer and parser errors: {
25184- text:        (matched text)
25185- token:       (the produced terminal token, if any)
25186- line:        (yylineno)
25187- }
25188- while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
25189- loc:         (yylloc)
25190- expected:    (string describing the set of expected tokens)
25191- recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
25192- }
25193- */
25194-var Parser = (function(){
25195-  var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,4],$V1=[1,5],$V2=[1,7],$V3=[1,10],$V4=[1,8],$V5=[1,9],$V6=[1,11],$V7=[1,16],$V8=[1,17],$V9=[1,14],$Va=[1,15],$Vb=[1,18],$Vc=[1,20],$Vd=[1,21],$Ve=[1,22],$Vf=[1,23],$Vg=[1,24],$Vh=[1,25],$Vi=[1,26],$Vj=[1,27],$Vk=[1,28],$Vl=[1,29],$Vm=[5,11,12,13,15,16,17,18,19,20,21,22,30,31],$Vn=[5,11,12,13,15,16,17,18,19,20,21,22,30,31,33],$Vo=[1,38],$Vp=[5,11,12,13,15,16,17,18,19,20,21,22,30,31,35],$Vq=[5,12,13,15,16,17,18,19,30,31],$Vr=[5,12,15,16,17,18,30,31],$Vs=[5,12,13,15,16,17,18,19,20,21,30,31],$Vt=[15,30,31],$Vu=[5,11,12,13,15,16,17,18,19,20,21,22,30,31,32,36];
25196-  var parser = {trace: function trace() { },
25197-    yy: {},
25198-    symbols_: {"error":2,"expressions":3,"expression":4,"EOF":5,"variableSequence":6,"TIME_AMPM":7,"TIME_24":8,"number":9,"STRING":10,"&":11,"=":12,"+":13,"(":14,")":15,"<":16,">":17,"NOT":18,"-":19,"*":20,"/":21,"^":22,"FUNCTION":23,"expseq":24,"cell":25,"FIXEDCELL":26,":":27,"CELL":28,"ARRAY":29,";":30,",":31,"VARIABLE":32,"DECIMAL":33,"NUMBER":34,"%":35,"#":36,"!":37,"$accept":0,"$end":1},
25199-    terminals_: {5:"EOF",7:"TIME_AMPM",8:"TIME_24",10:"STRING",11:"&",12:"=",13:"+",14:"(",15:")",16:"<",17:">",18:"NOT",19:"-",20:"*",21:"/",22:"^",23:"FUNCTION",26:"FIXEDCELL",27:":",28:"CELL",29:"ARRAY",30:";",31:",",32:"VARIABLE",33:"DECIMAL",34:"NUMBER",35:"%",36:"#",37:"!"},
25200-    productions_: [0,[3,2],[4,1],[4,1],[4,1],[4,1],[4,1],[4,3],[4,3],[4,3],[4,3],[4,4],[4,4],[4,4],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,2],[4,2],[4,3],[4,4],[4,1],[4,1],[4,2],[25,1],[25,3],[25,1],[25,3],[24,1],[24,1],[24,3],[24,3],[6,1],[6,3],[9,1],[9,3],[9,2],[2,3],[2,4]],
25201-    performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
25202-      /* this == yyval */
25203-
25204-      var $0 = $$.length - 1;
25205-      switch (yystate) {
25206-        case 1:
25207-
25208-          return $$[$0-1];
25209-
25210-          break;
25211-        case 2:
25212-
25213-          this.$ = yy.handler.helper.callVariable.call(this, $$[$0]);
25214-
25215-          break;
25216-        case 3:
25217-
25218-          this.$ = yy.handler.time.call(yy.obj, $$[$0], true);
25219-
25220-          break;
25221-        case 4:
25222-
25223-          this.$ = yy.handler.time.call(yy.obj, $$[$0]);
25224-
25225-          break;
25226-        case 5:
25227-
25228-          this.$ = yy.handler.helper.number($$[$0]);
25229-
25230-          break;
25231-        case 6:
25232-
25233-          this.$ = yy.handler.helper.string($$[$0]);
25234-
25235-          break;
25236-        case 7:
25237-
25238-          this.$ = yy.handler.helper.specialMatch('&', $$[$0-2], $$[$0]);
25239-
25240-          break;
25241-        case 8:
25242-
25243-          this.$ = yy.handler.helper.logicMatch('=', $$[$0-2], $$[$0]);
25244-
25245-          break;
25246-        case 9:
25247-
25248-          this.$ = yy.handler.helper.mathMatch('+', $$[$0-2], $$[$0]);
25249-
25250-          break;
25251-        case 10:
25252-
25253-          this.$ = yy.handler.helper.number($$[$0-1]);
25254-
25255-          break;
25256-        case 11:
25257-
25258-          this.$ = yy.handler.helper.logicMatch('<=', $$[$0-3], $$[$0]);
25259-
25260-          break;
25261-        case 12:
25262-
25263-          this.$ = yy.handler.helper.logicMatch('>=', $$[$0-3], $$[$0]);
25264-
25265-          break;
25266-        case 13:
25267-
25268-          this.$ = yy.handler.helper.logicMatch('<>', $$[$0-3], $$[$0]);
25269-
25270-          break;
25271-        case 14:
25272-
25273-          this.$ = yy.handler.helper.logicMatch('NOT', $$[$0-2], $$[$0]);
25274-
25275-          break;
25276-        case 15:
25277-
25278-          this.$ = yy.handler.helper.logicMatch('>', $$[$0-2], $$[$0]);
25279-
25280-          break;
25281-        case 16:
25282-
25283-          this.$ = yy.handler.helper.logicMatch('<', $$[$0-2], $$[$0]);
25284-
25285-          break;
25286-        case 17:
25287-
25288-          this.$ = yy.handler.helper.mathMatch('-', $$[$0-2], $$[$0]);
25289-
25290-          break;
25291-        case 18:
25292-
25293-          this.$ = yy.handler.helper.mathMatch('*', $$[$0-2], $$[$0]);
25294-
25295-          break;
25296-        case 19:
25297-
25298-          this.$ = yy.handler.helper.mathMatch('/', $$[$0-2], $$[$0]);
25299-
25300-          break;
25301-        case 20:
25302-
25303-          this.$ = yy.handler.helper.mathMatch('^', $$[$0-2], $$[$0]);
25304-
25305-          break;
25306-        case 21:
25307-
25308-          var n1 = yy.handler.helper.numberInverted($$[$0]);
25309-          this.$ = n1;
25310-          if (isNaN(this.$)) {
25311-            this.$ = 0;
25312-          }
25313-
25314-          break;
25315-        case 22:
25316-
25317-          var n1 = yy.handler.helper.number($$[$0]);
25318-          this.$ = n1;
25319-          if (isNaN(this.$)) {
25320-            this.$ = 0;
25321-          }
25322-
25323-          break;
25324-        case 23:
25325-
25326-          this.$ = yy.handler.helper.callFunction.call(this, $$[$0-2], '');
25327-
25328-          break;
25329-        case 24:
25330-
25331-          this.$ = yy.handler.helper.callFunction.call(this, $$[$0-3], $$[$0-1]);
25332-
25333-          break;
25334-        case 28:
25335-
25336-          this.$ = yy.handler.helper.fixedCellValue.call(yy.obj, $$[$0]);
25337-
25338-          break;
25339-        case 29:
25340-
25341-          this.$ = yy.handler.helper.fixedCellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
25342-
25343-          break;
25344-        case 30:
25345-
25346-          this.$ = yy.handler.helper.cellValue.call(yy.obj, $$[$0]);
25347-
25348-          break;
25349-        case 31:
25350-
25351-          this.$ = yy.handler.helper.cellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
25352-
25353-          break;
25354-        case 32:
25355-
25356-          if (yy.handler.utils.isArray($$[$0])) {
25357-            this.$ = $$[$0];
25358-          } else {
25359-            this.$ = [$$[$0]];
25360-          }
25361-
25362-          break;
25363-        case 33:
25364-
25365-          var result = [],
25366-            arr = eval("[" + yytext + "]");
25367-
25368-          arr.forEach(function (item) {
25369-            result.push(item);
25370-          });
25371-
25372-          this.$ = result;
25373-
25374-          break;
25375-        case 34: case 35:
25376-
25377-        $$[$0-2].push($$[$0]);
25378-        this.$ = $$[$0-2];
25379-
25380-        break;
25381-        case 36:
25382-
25383-          this.$ = [$$[$0]];
25384-
25385-          break;
25386-        case 37:
25387-
25388-          this.$ = (yy.handler.utils.isArray($$[$0-2]) ? $$[$0-2] : [$$[$0-2]]);
25389-          this.$.push($$[$0]);
25390-
25391-          break;
25392-        case 38:
25393-
25394-          this.$ = $$[$0];
25395-
25396-          break;
25397-        case 39:
25398-
25399-          this.$ = ($$[$0-2] + '.' + $$[$0]) * 1;
25400-
25401-          break;
25402-        case 40:
25403-
25404-          this.$ = $$[$0-1] * 0.01;
25405-
25406-          break;
25407-        case 41: case 42:
25408-
25409-        this.$ = $$[$0-2] + $$[$0-1] + $$[$0];
25410-
25411-        break;
25412-      }
25413-    },
25414-    table: [{2:13,3:1,4:2,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{1:[3]},{5:[1,19],11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl},o($Vm,[2,2],{33:[1,30]}),o($Vm,[2,3]),o($Vm,[2,4]),o($Vm,[2,5],{35:[1,31]}),o($Vm,[2,6]),{2:13,4:32,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:33,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:34,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{14:[1,35]},o($Vm,[2,25]),o($Vm,[2,26],{2:36,32:[1,37],36:$Vb}),o($Vn,[2,36],{36:$Vo}),o($Vp,[2,38],{33:[1,39]}),o($Vm,[2,28],{27:[1,40]}),o($Vm,[2,30],{27:[1,41]}),{32:[1,42]},{1:[2,1]},{2:13,4:43,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:44,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:45,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:48,6:3,7:$V0,8:$V1,9:6,10:$V2,12:[1,46],13:$V3,14:$V4,17:[1,47],19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:50,6:3,7:$V0,8:$V1,9:6,10:$V2,12:[1,49],13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:51,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:52,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:53,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:54,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:55,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{32:[1,56]},o($Vp,[2,40]),{11:$Vc,12:$Vd,13:$Ve,15:[1,57],16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl},o($Vq,[2,21],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),o($Vq,[2,22],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),{2:13,4:60,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,15:[1,58],19:$V5,23:$V6,24:59,25:12,26:$V7,28:$V8,29:[1,61],32:$V9,34:$Va,36:$Vb},o($Vm,[2,27]),{36:$Vo},{32:[1,62]},{34:[1,63]},{26:[1,64]},{28:[1,65]},{37:[1,66]},o($Vm,[2,7]),o([5,12,15,30,31],[2,8],{11:$Vc,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vq,[2,9],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),{2:13,4:67,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:68,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},o($Vr,[2,16],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),{2:13,4:69,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},o($Vr,[2,15],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o([5,12,15,18,30,31],[2,14],{11:$Vc,13:$Ve,16:$Vf,17:$Vg,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vq,[2,17],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),o($Vs,[2,18],{11:$Vc,22:$Vl}),o($Vs,[2,19],{11:$Vc,22:$Vl}),o([5,12,13,15,16,17,18,19,20,21,22,30,31],[2,20],{11:$Vc}),o($Vn,[2,37]),o($Vm,[2,10]),o($Vm,[2,23]),{15:[1,70],30:[1,71],31:[1,72]},o($Vt,[2,32],{11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vt,[2,33]),{37:[1,73]},o($Vp,[2,39]),o($Vm,[2,29]),o($Vm,[2,31]),o($Vu,[2,41]),o($Vr,[2,11],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vr,[2,13],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vr,[2,12],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vm,[2,24]),{2:13,4:74,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:75,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},o($Vu,[2,42]),o($Vt,[2,34],{11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vt,[2,35],{11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl})],
25415-    defaultActions: {19:[2,1]},
25416-    parseError: function parseError(str, hash) {
25417-      if (hash.recoverable) {
25418-        this.trace(str);
25419-      } else {
25420-        throw new Error(str);
25421-      }
25422-    },
25423-    parse: function parse(input) {
25424-      var self = this,
25425-        stack = [0],
25426-        tstack = [], // token stack
25427-        vstack = [null], // semantic value stack
25428-        lstack = [], // location stack
25429-        table = this.table,
25430-        yytext = '',
25431-        yylineno = 0,
25432-        yyleng = 0,
25433-        recovering = 0,
25434-        TERROR = 2,
25435-        EOF = 1;
25436-
25437-      var args = lstack.slice.call(arguments, 1);
25438-
25439-      //this.reductionCount = this.shiftCount = 0;
25440-
25441-      var lexer = Object.create(this.lexer);
25442-      var sharedState = { yy: {} };
25443-      // copy state
25444-      for (var k in this.yy) {
25445-        if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
25446-          sharedState.yy[k] = this.yy[k];
25447-        }
25448-      }
25449-
25450-      lexer.setInput(input, sharedState.yy);
25451-      sharedState.yy.lexer = lexer;
25452-      sharedState.yy.parser = this;
25453-      if (typeof lexer.yylloc == 'undefined') {
25454-        lexer.yylloc = {};
25455-      }
25456-      var yyloc = lexer.yylloc;
25457-      lstack.push(yyloc);
25458-
25459-      var ranges = lexer.options && lexer.options.ranges;
25460-
25461-      if (typeof sharedState.yy.parseError === 'function') {
25462-        this.parseError = sharedState.yy.parseError;
25463-      } else {
25464-        this.parseError = Object.getPrototypeOf(this).parseError;
25465-      }
25466-
25467-      function popStack (n) {
25468-        stack.length = stack.length - 2 * n;
25469-        vstack.length = vstack.length - n;
25470-        lstack.length = lstack.length - n;
25471-      }
25472-
25473-      _token_stack:
25474-        function lex() {
25475-          var token;
25476-          token = lexer.lex() || EOF;
25477-          // if token isn't its numeric value, convert
25478-          if (typeof token !== 'number') {
25479-            token = self.symbols_[token] || token;
25480-          }
25481-          return token;
25482-        }
25483-
25484-      var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
25485-      while (true) {
25486-        // retreive state number from top of stack
25487-        state = stack[stack.length - 1];
25488-
25489-        // use default actions if available
25490-        if (this.defaultActions[state]) {
25491-          action = this.defaultActions[state];
25492-        } else {
25493-          if (symbol === null || typeof symbol == 'undefined') {
25494-            symbol = lex();
25495-          }
25496-          // read action for current state and first input
25497-          action = table[state] && table[state][symbol];
25498-        }
25499-
25500-        _handle_error:
25501-          // handle parse error
25502-          if (typeof action === 'undefined' || !action.length || !action[0]) {
25503-            var error_rule_depth;
25504-            var errStr = '';
25505-
25506-            // Return the rule stack depth where the nearest error rule can be found.
25507-            // Return FALSE when no error recovery rule was found.
25508-            function locateNearestErrorRecoveryRule(state) {
25509-              var stack_probe = stack.length - 1;
25510-              var depth = 0;
25511-
25512-              // try to recover from error
25513-              for(;;) {
25514-                // check for error recovery rule in this state
25515-                if ((TERROR.toString()) in table[state]) {
25516-                  return depth;
25517-                }
25518-                if (state === 0 || stack_probe < 2) {
25519-                  return false; // No suitable error recovery rule available.
25520-                }
25521-                stack_probe -= 2; // popStack(1): [symbol, action]
25522-                state = stack[stack_probe];
25523-                ++depth;
25524-              }
25525-            }
25526-
25527-            if (!recovering) {
25528-              // first see if there's any chance at hitting an error recovery rule:
25529-              error_rule_depth = locateNearestErrorRecoveryRule(state);
25530-
25531-              // Report error
25532-              expected = [];
25533-              for (p in table[state]) {
25534-                if (this.terminals_[p] && p > TERROR) {
25535-                  expected.push("'"+this.terminals_[p]+"'");
25536-                }
25537-              }
25538-              if (lexer.showPosition) {
25539-                errStr = 'Parse error on line '+(yylineno+1)+":\n"+lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + (this.terminals_[symbol] || symbol)+ "'";
25540-              } else {
25541-                errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
25542-                  (symbol == EOF ? "end of input" :
25543-                    ("'"+(this.terminals_[symbol] || symbol)+"'"));
25544-              }
25545-              this.parseError(errStr, {
25546-                text: lexer.match,
25547-                token: this.terminals_[symbol] || symbol,
25548-                line: lexer.yylineno,
25549-                loc: yyloc,
25550-                expected: expected,
25551-                recoverable: (error_rule_depth !== false)
25552-              });
25553-            } else if (preErrorSymbol !== EOF) {
25554-              error_rule_depth = locateNearestErrorRecoveryRule(state);
25555-            }
25556-
25557-            // just recovered from another error
25558-            if (recovering == 3) {
25559-              if (symbol === EOF || preErrorSymbol === EOF) {
25560-                throw new Error(errStr || 'Parsing halted while starting to recover from another error.');
25561-              }
25562-
25563-              // discard current lookahead and grab another
25564-              yyleng = lexer.yyleng;
25565-              yytext = lexer.yytext;
25566-              yylineno = lexer.yylineno;
25567-              yyloc = lexer.yylloc;
25568-              symbol = lex();
25569-            }
25570-
25571-            // try to recover from error
25572-            if (error_rule_depth === false) {
25573-              throw new Error(errStr || 'Parsing halted. No suitable error recovery rule available.');
25574-            }
25575-            popStack(error_rule_depth);
25576-
25577-            preErrorSymbol = (symbol == TERROR ? null : symbol); // save the lookahead token
25578-            symbol = TERROR;         // insert generic error symbol as new lookahead
25579-            state = stack[stack.length-1];
25580-            action = table[state] && table[state][TERROR];
25581-            recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
25582-          }
25583-
25584-        // this shouldn't happen, unless resolve defaults are off
25585-        if (action[0] instanceof Array && action.length > 1) {
25586-          throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
25587-        }
25588-
25589-        switch (action[0]) {
25590-          case 1: // shift
25591-            //this.shiftCount++;
25592-
25593-            stack.push(symbol);
25594-            vstack.push(lexer.yytext);
25595-            lstack.push(lexer.yylloc);
25596-            stack.push(action[1]); // push state
25597-            symbol = null;
25598-            if (!preErrorSymbol) { // normal execution/no error
25599-              yyleng = lexer.yyleng;
25600-              yytext = lexer.yytext;
25601-              yylineno = lexer.yylineno;
25602-              yyloc = lexer.yylloc;
25603-              if (recovering > 0) {
25604-                recovering--;
25605-              }
25606-            } else {
25607-              // error just occurred, resume old lookahead f/ before error
25608-              symbol = preErrorSymbol;
25609-              preErrorSymbol = null;
25610-            }
25611-            break;
25612-
25613-          case 2:
25614-            // reduce
25615-            //this.reductionCount++;
25616-
25617-            len = this.productions_[action[1]][1];
25618-
25619-            // perform semantic action
25620-            yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
25621-            // default location, uses first token for firsts, last for lasts
25622-            yyval._$ = {
25623-              first_line: lstack[lstack.length-(len||1)].first_line,
25624-              last_line: lstack[lstack.length-1].last_line,
25625-              first_column: lstack[lstack.length-(len||1)].first_column,
25626-              last_column: lstack[lstack.length-1].last_column
25627-            };
25628-            if (ranges) {
25629-              yyval._$.range = [lstack[lstack.length-(len||1)].range[0], lstack[lstack.length-1].range[1]];
25630-            }
25631-            r = this.performAction.apply(yyval, [yytext, yyleng, yylineno, sharedState.yy, action[1], vstack, lstack].concat(args));
25632-
25633-            if (typeof r !== 'undefined') {
25634-              return r;
25635-            }
25636-
25637-            // pop off stack
25638-            if (len) {
25639-              stack = stack.slice(0,-1*len*2);
25640-              vstack = vstack.slice(0, -1*len);
25641-              lstack = lstack.slice(0, -1*len);
25642-            }
25643-
25644-            stack.push(this.productions_[action[1]][0]);    // push nonterminal (reduce)
25645-            vstack.push(yyval.$);
25646-            lstack.push(yyval._$);
25647-            // goto new state = table[STATE][NONTERMINAL]
25648-            newState = table[stack[stack.length-2]][stack[stack.length-1]];
25649-            stack.push(newState);
25650-            break;
25651-
25652-          case 3:
25653-            // accept
25654-            return true;
25655-        }
25656-
25657-      }
25658-
25659-      return true;
25660-    }};
25661-
25662-  /* generated by jison-lex 0.3.4 */
25663-  var lexer = (function(){
25664-    var lexer = ({
25665-
25666-      EOF:1,
25667-
25668-      parseError:function parseError(str, hash) {
25669-        if (this.yy.parser) {
25670-          this.yy.parser.parseError(str, hash);
25671-        } else {
25672-          throw new Error(str);
25673-        }
25674-      },
25675-
25676-// resets the lexer, sets new input
25677-      setInput:function (input, yy) {
25678-        this.yy = yy || this.yy || {};
25679-        this._input = input;
25680-        this._more = this._backtrack = this.done = false;
25681-        this.yylineno = this.yyleng = 0;
25682-        this.yytext = this.matched = this.match = '';
25683-        this.conditionStack = ['INITIAL'];
25684-        this.yylloc = {
25685-          first_line: 1,
25686-          first_column: 0,
25687-          last_line: 1,
25688-          last_column: 0
25689-        };
25690-        if (this.options.ranges) {
25691-          this.yylloc.range = [0,0];
25692-        }
25693-        this.offset = 0;
25694-        return this;
25695-      },
25696-
25697-// consumes and returns one char from the input
25698-      input:function () {
25699-        var ch = this._input[0];
25700-        this.yytext += ch;
25701-        this.yyleng++;
25702-        this.offset++;
25703-        this.match += ch;
25704-        this.matched += ch;
25705-        var lines = ch.match(/(?:\r\n?|\n).*/g);
25706-        if (lines) {
25707-          this.yylineno++;
25708-          this.yylloc.last_line++;
25709-        } else {
25710-          this.yylloc.last_column++;
25711-        }
25712-        if (this.options.ranges) {
25713-          this.yylloc.range[1]++;
25714-        }
25715-
25716-        this._input = this._input.slice(1);
25717-        return ch;
25718-      },
25719-
25720-// unshifts one char (or a string) into the input
25721-      unput:function (ch) {
25722-        var len = ch.length;
25723-        var lines = ch.split(/(?:\r\n?|\n)/g);
25724-
25725-        this._input = ch + this._input;
25726-        this.yytext = this.yytext.substr(0, this.yytext.length - len);
25727-        //this.yyleng -= len;
25728-        this.offset -= len;
25729-        var oldLines = this.match.split(/(?:\r\n?|\n)/g);
25730-        this.match = this.match.substr(0, this.match.length - 1);
25731-        this.matched = this.matched.substr(0, this.matched.length - 1);
25732-
25733-        if (lines.length - 1) {
25734-          this.yylineno -= lines.length - 1;
25735-        }
25736-        var r = this.yylloc.range;
25737-
25738-        this.yylloc = {
25739-          first_line: this.yylloc.first_line,
25740-          last_line: this.yylineno + 1,
25741-          first_column: this.yylloc.first_column,
25742-          last_column: lines ?
25743-          (lines.length === oldLines.length ? this.yylloc.first_column : 0)
25744-          + oldLines[oldLines.length - lines.length].length - lines[0].length :
25745-          this.yylloc.first_column - len
25746-        };
25747-
25748-        if (this.options.ranges) {
25749-          this.yylloc.range = [r[0], r[0] + this.yyleng - len];
25750-        }
25751-        this.yyleng = this.yytext.length;
25752-        return this;
25753-      },
25754-
25755-// When called from action, caches matched text and appends it on next action
25756-      more:function () {
25757-        this._more = true;
25758-        return this;
25759-      },
25760-
25761-// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
25762-      reject:function () {
25763-        if (this.options.backtrack_lexer) {
25764-          this._backtrack = true;
25765-        } else {
25766-          return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
25767-            text: "",
25768-            token: null,
25769-            line: this.yylineno
25770-          });
25771-
25772-        }
25773-        return this;
25774-      },
25775-
25776-// retain first n characters of the match
25777-      less:function (n) {
25778-        this.unput(this.match.slice(n));
25779-      },
25780-
25781-// displays already matched input, i.e. for error messages
25782-      pastInput:function () {
25783-        var past = this.matched.substr(0, this.matched.length - this.match.length);
25784-        return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
25785-      },
25786-
25787-// displays upcoming input, i.e. for error messages
25788-      upcomingInput:function () {
25789-        var next = this.match;
25790-        if (next.length < 20) {
25791-          next += this._input.substr(0, 20-next.length);
25792-        }
25793-        return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
25794-      },
25795-
25796-// displays the character position where the lexing error occurred, i.e. for error messages
25797-      showPosition:function () {
25798-        var pre = this.pastInput();
25799-        var c = new Array(pre.length + 1).join("-");
25800-        return pre + this.upcomingInput() + "\n" + c + "^";
25801-      },
25802-
25803-// test the lexed token: return FALSE when not a match, otherwise return token
25804-      test_match:function (match, indexed_rule) {
25805-        var token,
25806-          lines,
25807-          backup;
25808-
25809-        if (this.options.backtrack_lexer) {
25810-          // save context
25811-          backup = {
25812-            yylineno: this.yylineno,
25813-            yylloc: {
25814-              first_line: this.yylloc.first_line,
25815-              last_line: this.last_line,
25816-              first_column: this.yylloc.first_column,
25817-              last_column: this.yylloc.last_column
25818-            },
25819-            yytext: this.yytext,
25820-            match: this.match,
25821-            matches: this.matches,
25822-            matched: this.matched,
25823-            yyleng: this.yyleng,
25824-            offset: this.offset,
25825-            _more: this._more,
25826-            _input: this._input,
25827-            yy: this.yy,
25828-            conditionStack: this.conditionStack.slice(0),
25829-            done: this.done
25830-          };
25831-          if (this.options.ranges) {
25832-            backup.yylloc.range = this.yylloc.range.slice(0);
25833-          }
25834-        }
25835-
25836-        lines = match[0].match(/(?:\r\n?|\n).*/g);
25837-        if (lines) {
25838-          this.yylineno += lines.length;
25839-        }
25840-        this.yylloc = {
25841-          first_line: this.yylloc.last_line,
25842-          last_line: this.yylineno + 1,
25843-          first_column: this.yylloc.last_column,
25844-          last_column: lines ?
25845-          lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
25846-          this.yylloc.last_column + match[0].length
25847-        };
25848-        this.yytext += match[0];
25849-        this.match += match[0];
25850-        this.matches = match;
25851-        this.yyleng = this.yytext.length;
25852-        if (this.options.ranges) {
25853-          this.yylloc.range = [this.offset, this.offset += this.yyleng];
25854-        }
25855-        this._more = false;
25856-        this._backtrack = false;
25857-        this._input = this._input.slice(match[0].length);
25858-        this.matched += match[0];
25859-        token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
25860-        if (this.done && this._input) {
25861-          this.done = false;
25862-        }
25863-        if (token) {
25864-          return token;
25865-        } else if (this._backtrack) {
25866-          // recover context
25867-          for (var k in backup) {
25868-            this[k] = backup[k];
25869-          }
25870-          return false; // rule action called reject() implying the next rule should be tested instead.
25871-        }
25872-        return false;
25873-      },
25874-
25875-// return next match in input
25876-      next:function () {
25877-        if (this.done) {
25878-          return this.EOF;
25879-        }
25880-        if (!this._input) {
25881-          this.done = true;
25882-        }
25883-
25884-        var token,
25885-          match,
25886-          tempMatch,
25887-          index;
25888-        if (!this._more) {
25889-          this.yytext = '';
25890-          this.match = '';
25891-        }
25892-        var rules = this._currentRules();
25893-        for (var i = 0; i < rules.length; i++) {
25894-          tempMatch = this._input.match(this.rules[rules[i]]);
25895-          if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
25896-            match = tempMatch;
25897-            index = i;
25898-            if (this.options.backtrack_lexer) {
25899-              token = this.test_match(tempMatch, rules[i]);
25900-              if (token !== false) {
25901-                return token;
25902-              } else if (this._backtrack) {
25903-                match = false;
25904-                continue; // rule action called reject() implying a rule MISmatch.
25905-              } else {
25906-                // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
25907-                return false;
25908-              }
25909-            } else if (!this.options.flex) {
25910-              break;
25911-            }
25912-          }
25913-        }
25914-        if (match) {
25915-          token = this.test_match(match, rules[index]);
25916-          if (token !== false) {
25917-            return token;
25918-          }
25919-          // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
25920-          return false;
25921-        }
25922-        if (this._input === "") {
25923-          return this.EOF;
25924-        } else {
25925-          return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
25926-            text: "",
25927-            token: null,
25928-            line: this.yylineno
25929-          });
25930-        }
25931-      },
25932-
25933-// return next match that has a token
25934-      lex:function lex() {
25935-        var r = this.next();
25936-        if (r) {
25937-          return r;
25938-        } else {
25939-          return this.lex();
25940-        }
25941-      },
25942-
25943-// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
25944-      begin:function begin(condition) {
25945-        this.conditionStack.push(condition);
25946-      },
25947-
25948-// pop the previously active lexer condition state off the condition stack
25949-      popState:function popState() {
25950-        var n = this.conditionStack.length - 1;
25951-        if (n > 0) {
25952-          return this.conditionStack.pop();
25953-        } else {
25954-          return this.conditionStack[0];
25955-        }
25956-      },
25957-
25958-// produce the lexer rule set which is active for the currently active lexer condition state
25959-      _currentRules:function _currentRules() {
25960-        if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
25961-          return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
25962-        } else {
25963-          return this.conditions["INITIAL"].rules;
25964-        }
25965-      },
25966-
25967-// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
25968-      topState:function topState(n) {
25969-        n = this.conditionStack.length - 1 - Math.abs(n || 0);
25970-        if (n >= 0) {
25971-          return this.conditionStack[n];
25972-        } else {
25973-          return "INITIAL";
25974-        }
25975-      },
25976-
25977-// alias for begin(condition)
25978-      pushState:function pushState(condition) {
25979-        this.begin(condition);
25980-      },
25981-
25982-// return the number of states currently on the stack
25983-      stateStackSize:function stateStackSize() {
25984-        return this.conditionStack.length;
25985-      },
25986-      options: {},
25987-      performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
25988-        var YYSTATE=YY_START;
25989-        switch($avoiding_name_collisions) {
25990-          case 0:/* skip whitespace */
25991-            break;
25992-          case 1:return 10;
25993-            break;
25994-          case 2:return 10;
25995-            break;
25996-          case 3:return 23;
25997-            break;
25998-          case 4:return 7;
25999-            break;
26000-          case 5:return 8;
26001-            break;
26002-          case 6:
26003-            //if (yy.obj.type == 'cell') return 26;
26004-            //return 32;
26005-            return 26
26006-
26007-            break;
26008-          case 7:
26009-            //if (yy.obj.type == 'cell') return 28;
26010-            //return 32;
26011-            return 28;
26012-
26013-            break;
26014-          case 8:return 23;
26015-            break;
26016-          case 9:return 32;
26017-            break;
26018-          case 10:return 32;
26019-            break;
26020-          case 11:return 34;
26021-            break;
26022-          case 12:return 29;
26023-            break;
26024-          case 13:/* skip whitespace */
26025-            break;
26026-          case 14:return 11;
26027-            break;
26028-          case 15:return ' ';
26029-            break;
26030-          case 16:return 33;
26031-            break;
26032-          case 17:return 27;
26033-            break;
26034-          case 18:return 30;
26035-            break;
26036-          case 19:return 31;
26037-            break;
26038-          case 20:return 20;
26039-            break;
26040-          case 21:return 21;
26041-            break;
26042-          case 22:return 19;
26043-            break;
26044-          case 23:return 13;
26045-            break;
26046-          case 24:return 22;
26047-            break;
26048-          case 25:return 14;
26049-            break;
26050-          case 26:return 15;
26051-            break;
26052-          case 27:return 17;
26053-            break;
26054-          case 28:return 16;
26055-            break;
26056-          case 29:return 18;
26057-            break;
26058-          case 30:return '"';
26059-            break;
26060-          case 31:return "'";
26061-            break;
26062-          case 32:return "!";
26063-            break;
26064-          case 33:return 12;
26065-            break;
26066-          case 34:return 35;
26067-            break;
26068-          case 35:return 36;
26069-            break;
26070-          case 36:return 5;
26071-            break;
26072-        }
26073-      },
26074-      rules: [/^(?:\s+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:[A-Za-z]{1,}[A-Za-z_0-9]+(?=[(]))/,/^(?:([0]?[1-9]|1[0-2])[:][0-5][0-9]([:][0-5][0-9])?[ ]?(AM|am|aM|Am|PM|pm|pM|Pm))/,/^(?:([0]?[0-9]|1[0-9]|2[0-3])[:][0-5][0-9]([:][0-5][0-9])?)/,/^(?:\$[A-Za-z]+\$[0-9]+)/,/^(?:[A-Za-z]+[0-9]+)/,/^(?:[A-Za-z]+(?=[(]))/,/^(?:[A-Za-z]{1,}[A-Za-z_0-9]+)/,/^(?:[A-Za-z_]+)/,/^(?:[0-9]+)/,/^(?:\[(.*)?\])/,/^(?:\$)/,/^(?:&)/,/^(?: )/,/^(?:[.])/,/^(?::)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\/)/,/^(?:-)/,/^(?:\+)/,/^(?:\^)/,/^(?:\()/,/^(?:\))/,/^(?:>)/,/^(?:<)/,/^(?:NOT\b)/,/^(?:")/,/^(?:')/,/^(?:!)/,/^(?:=)/,/^(?:%)/,/^(?:[#])/,/^(?:$)/],
26075-      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,29,30,31,32,33,34,35,36],"inclusive":true}}
26076-    });
26077-    return lexer;
26078-  })();
26079-  parser.lexer = lexer;
26080-  function Parser () {
26081-    this.yy = {};
26082-  }
26083-  Parser.prototype = parser;parser.Parser = Parser;
26084-  return new Parser;
26085-})();
26086\ No newline at end of file
26087diff --git a/ts/sheet.js b/ts/sheet.js
26088deleted file mode 100644
26089index 1c26f79..0000000
26090--- a/ts/sheet.js
26091+++ /dev/null
26092@@ -1,556 +0,0 @@
26093-/**
26094- * A1-notation style cell id. Used to index the cells.
26095- * */
26096-var A1CellKey = (function () {
26097-    function A1CellKey(key) {
26098-        this.row = parseInt(key.match(/\d+$/)[0], 10);
26099-        this.column = key.replace(this.row.toString(), '');
26100-        this.x = lettersToNumber(this.column);
26101-        this.y = this.row - 1;
26102-    }
26103-    A1CellKey.of = function (x, y) {
26104-        return new A1CellKey(numberToLetters(x + 1) + (y + 1).toString());
26105-    };
26106-    A1CellKey.prototype.toString = function () {
26107-        return this.column + "" + this.row;
26108-    };
26109-    A1CellKey.prototype.getColumn = function () {
26110-        return this.column;
26111-    };
26112-    A1CellKey.prototype.getRow = function () {
26113-        return this.row;
26114-    };
26115-    A1CellKey.prototype.getX = function () {
26116-        return this.x;
26117-    };
26118-    A1CellKey.prototype.getY = function () {
26119-        return this.y;
26120-    };
26121-    return A1CellKey;
26122-}());
26123-function lettersToNumber(letters) {
26124-    return letters.toLowerCase().charCodeAt(0) - 97;
26125-}
26126-function numberToLetters(num) {
26127-    var mod = num % 26, pow = num / 26 | 0, out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
26128-    return pow ? numberToLetters(pow) + out : out;
26129-}
26130-var Cell = (function () {
26131-    function Cell(formula, id) {
26132-        this.formula = formula;
26133-        this.value = "";
26134-        this.dependencies = [];
26135-        this.error = null;
26136-        this.id = id;
26137-    }
26138-    Cell.prototype.updateDependencies = function (dependencies) {
26139-        for (var index in dependencies) {
26140-            if (this.dependencies.indexOf(dependencies[index]) === -1) {
26141-                this.dependencies.push(dependencies[index]);
26142-            }
26143-        }
26144-    };
26145-    Cell.prototype.setValue = function (value) {
26146-        this.value = value;
26147-    };
26148-    Cell.prototype.setError = function (error) {
26149-        this.error = error;
26150-    };
26151-    return Cell;
26152-}());
26153-var Sheet = (function () {
26154-    'use strict';
26155-    var instance = this;
26156-    // Will be overwritten, but needs to be initialized, and have some functions for tsc compilation.
26157-    var parser = {
26158-        setObj: function (obj) { },
26159-        parse: function (formula) { }
26160-    };
26161-    var FormulaParser = function (handler) {
26162-        var formulaLexer = function () { };
26163-        formulaLexer.prototype = Parser.lexer;
26164-        var formulaParser = function () {
26165-            this.lexer = new formulaLexer();
26166-            this.yy = {};
26167-        };
26168-        formulaParser.prototype = Parser;
26169-        var newParser = new formulaParser;
26170-        newParser.setObj = function (obj) {
26171-            newParser.yy.obj = obj;
26172-        };
26173-        newParser.yy.parseError = function (str, hash) {
26174-            throw {
26175-                name: 'Parser error',
26176-                message: str,
26177-                prop: hash
26178-            };
26179-        };
26180-        newParser.yy.handler = handler;
26181-        return newParser;
26182-    };
26183-    var Exception = {
26184-        errors: [
26185-            { type: 'NULL', output: '#NULL' },
26186-            { type: 'DIV_ZERO', output: '#DIV/0!' },
26187-            { type: 'VALUE', output: '#VALUE!' },
26188-            { type: 'REF', output: '#REF!' },
26189-            { type: 'NAME', output: '#NAME?' },
26190-            { type: 'NUM', output: '#NUM!' },
26191-            { type: 'NOT_AVAILABLE', output: '#N/A!' },
26192-            { type: 'ERROR', output: '#ERROR' }
26193-        ],
26194-        get: function (type) {
26195-            var error = Exception.errors.filter(function (item) {
26196-                return item.type === type || item.output === type;
26197-            })[0];
26198-            return error ? error.output : null;
26199-        }
26200-    };
26201-    var Matrix = (function () {
26202-        function Matrix() {
26203-            this.data = [];
26204-        }
26205-        Matrix.prototype.getItem = function (key) {
26206-            return this.data.filter(function (cell) {
26207-                return cell.id === key.toString();
26208-            })[0];
26209-        };
26210-        Matrix.prototype.addItem = function (cell) {
26211-            var cellId = cell.id;
26212-            var key = new A1CellKey(cellId);
26213-            var coords = instance.utils.cellCoords(cellId);
26214-            cell.row = coords.row;
26215-            cell.col = coords.col;
26216-            var existingCell = this.data.filter(function (cell) {
26217-                return cell.id === cellId;
26218-            })[0];
26219-            if (!existingCell) {
26220-                this.data.push(cell);
26221-            }
26222-            else {
26223-                this.getItem(key).updateDependencies(cell.dependencies);
26224-                this.getItem(key).setValue(cell.value);
26225-                this.getItem(key).setError(cell.error);
26226-            }
26227-            return this.getItem(new A1CellKey(cellId));
26228-        };
26229-        Matrix.prototype.getDependencies = function (id) {
26230-            var getDependencies = function (id) {
26231-                var filtered = this.data.filter(function (cell) {
26232-                    if (cell.deps) {
26233-                        return cell.deps.indexOf(id) > -1;
26234-                    }
26235-                });
26236-                var deps = [];
26237-                filtered.forEach(function (cell) {
26238-                    if (deps.indexOf(cell.id) === -1) {
26239-                        deps.push(cell.id);
26240-                    }
26241-                });
26242-                return deps;
26243-            }.bind(this);
26244-            var allDependencies = [];
26245-            var getTotalDependencies = function (id) {
26246-                var deps = getDependencies(id);
26247-                if (deps.length) {
26248-                    deps.forEach(function (refId) {
26249-                        if (allDependencies.indexOf(refId) === -1) {
26250-                            allDependencies.push(refId);
26251-                            var item = this.getItem(new A1CellKey(refId));
26252-                            if (item.deps.length) {
26253-                                getTotalDependencies(refId);
26254-                            }
26255-                        }
26256-                    });
26257-                }
26258-            }.bind(this);
26259-            getTotalDependencies(id);
26260-            return allDependencies;
26261-        };
26262-        Matrix.prototype.getCellDependencies = function (cell) {
26263-            return this.getDependencies(cell.id);
26264-        };
26265-        Matrix.prototype.scan = function () {
26266-            var input = [
26267-                [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "SUM(A1:D1, H1)"],
26268-                [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "MAX(A2:J2)"],
26269-                [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "MIN(A3:J3)"],
26270-                [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "AVERAGE(A4:J4)"],
26271-                [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "SUMIF(A5:J5,'>5')"]
26272-            ];
26273-            for (var y = 0; y < input.length; y++) {
26274-                for (var x = 0; x < input[0].length; x++) {
26275-                    // set the cell here
26276-                    var id = utils.XYtoA1(x, y);
26277-                    var cell = new Cell(input[y][x].toString(), id);
26278-                    registerCellInMatrix(cell);
26279-                    recalculateCellDependencies(cell);
26280-                }
26281-            }
26282-            this.data.forEach(function (item) {
26283-                console.log(item.id, item.formula, item.value);
26284-            });
26285-        };
26286-        return Matrix;
26287-    }());
26288-    var recalculateCellDependencies = function (cell) {
26289-        var allDependencies = instance.matrix.getCellDependencies(cell);
26290-        allDependencies.forEach(function (refId) {
26291-            var currentCell = instance.matrix.getItem(new A1CellKey(refId));
26292-            if (currentCell && currentCell.formula) {
26293-                calculateCellFormula(currentCell);
26294-            }
26295-        });
26296-    };
26297-    var calculateCellFormula = function (cell) {
26298-        // to avoid double translate formulas, update item data in parser
26299-        var parsed = parse(cell.formula, cell.id);
26300-        var key = new A1CellKey(cell.id);
26301-        // instance.matrix.updateCellItem(key, {value: value, error: error});
26302-        instance.matrix.getItem(key).setValue(parsed.result);
26303-        instance.matrix.getItem(key).setError(parsed.error);
26304-        return parsed;
26305-    };
26306-    var registerCellInMatrix = function (cell) {
26307-        instance.matrix.addItem(cell);
26308-        calculateCellFormula(cell);
26309-    };
26310-    var utils = {
26311-        isArray: function (value) {
26312-            return Object.prototype.toString.call(value) === '[object Array]';
26313-        },
26314-        isNumber: function (value) {
26315-            return Object.prototype.toString.call(value) === '[object Number]';
26316-        },
26317-        isString: function (value) {
26318-            return Object.prototype.toString.call(value) === '[object String]';
26319-        },
26320-        isFunction: function (value) {
26321-            return Object.prototype.toString.call(value) === '[object Function]';
26322-        },
26323-        isUndefined: function (value) {
26324-            return Object.prototype.toString.call(value) === '[object Undefined]';
26325-        },
26326-        isNull: function (value) {
26327-            return Object.prototype.toString.call(value) === '[object Null]';
26328-        },
26329-        isSet: function (value) {
26330-            return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
26331-        },
26332-        getCellAlphaNum: function (cell) {
26333-            var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
26334-            return {
26335-                alpha: alpha,
26336-                num: parseInt(num[0], 10)
26337-            };
26338-        },
26339-        toNum: function (chr) {
26340-            chr = instance.utils.clearFormula(chr);
26341-            var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
26342-            for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
26343-                result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
26344-            }
26345-            if (result) {
26346-                --result;
26347-            }
26348-            return result;
26349-        },
26350-        toChar: function (num) {
26351-            var s = '';
26352-            while (num >= 0) {
26353-                s = String.fromCharCode(num % 26 + 97) + s;
26354-                num = Math.floor(num / 26) - 1;
26355-            }
26356-            return s.toUpperCase();
26357-        },
26358-        XYtoA1: function (x, y) {
26359-            function numberToLetters(num) {
26360-                var mod = num % 26, pow = num / 26 | 0, out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
26361-                return pow ? numberToLetters(pow) + out : out;
26362-            }
26363-            return numberToLetters(x + 1) + (y + 1).toString();
26364-        },
26365-        cellCoords: function (cell) {
26366-            var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
26367-            return {
26368-                row: parseInt(num[0], 10) - 1,
26369-                col: instance.utils.toNum(alpha)
26370-            };
26371-        },
26372-        clearFormula: function (formula) {
26373-            return formula.replace(/\$/g, '');
26374-        },
26375-        translateCellCoords: function (coords) {
26376-            return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
26377-        },
26378-        iterateCells: function (startCell, endCell, callback) {
26379-            var result = {
26380-                index: [],
26381-                value: [] // list of cell value
26382-            };
26383-            var cols = {
26384-                start: 0,
26385-                end: 0
26386-            };
26387-            if (endCell.col >= startCell.col) {
26388-                cols = {
26389-                    start: startCell.col,
26390-                    end: endCell.col
26391-                };
26392-            }
26393-            else {
26394-                cols = {
26395-                    start: endCell.col,
26396-                    end: startCell.col
26397-                };
26398-            }
26399-            var rows = {
26400-                start: 0,
26401-                end: 0
26402-            };
26403-            if (endCell.row >= startCell.row) {
26404-                rows = {
26405-                    start: startCell.row,
26406-                    end: endCell.row
26407-                };
26408-            }
26409-            else {
26410-                rows = {
26411-                    start: endCell.row,
26412-                    end: startCell.row
26413-                };
26414-            }
26415-            for (var column = cols.start; column <= cols.end; column++) {
26416-                for (var row = rows.start; row <= rows.end; row++) {
26417-                    var cellIndex = instance.utils.toChar(column) + (row + 1), cellValue = instance.helper.cellValue.call(this, cellIndex);
26418-                    result.index.push(cellIndex);
26419-                    result.value.push(cellValue);
26420-                }
26421-            }
26422-            if (instance.utils.isFunction(callback)) {
26423-                return callback.apply(callback, [result]);
26424-            }
26425-            else {
26426-                return result;
26427-            }
26428-        },
26429-        sort: function (rev) {
26430-            return function (a, b) {
26431-                return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
26432-            };
26433-        }
26434-    };
26435-    var helper = {
26436-        SUPPORTED_FORMULAS: [
26437-            'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
26438-            'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
26439-            'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
26440-            'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
26441-            'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
26442-            'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
26443-            'IF', 'INT', 'ISEVEN', 'ISODD',
26444-            'LN', 'LOG', 'LOG10',
26445-            'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
26446-            'NOT',
26447-            'ODD', 'OR',
26448-            'PI', 'POWER',
26449-            'ROUND', 'ROUNDDOWN', 'ROUNDUP',
26450-            'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
26451-            'TAN', 'TANH', 'TRUE', 'TRUNC',
26452-            'XOR'
26453-        ],
26454-        number: function (num) {
26455-            switch (typeof num) {
26456-                case 'number':
26457-                    return num;
26458-                case 'string':
26459-                    if (!isNaN(num)) {
26460-                        return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
26461-                    }
26462-            }
26463-            return num;
26464-        },
26465-        string: function (str) {
26466-            return str.substring(1, str.length - 1);
26467-        },
26468-        numberInverted: function (num) {
26469-            return this.number(num) * (-1);
26470-        },
26471-        specialMatch: function (type, exp1, exp2) {
26472-            var result;
26473-            switch (type) {
26474-                case '&':
26475-                    result = exp1.toString() + exp2.toString();
26476-                    break;
26477-            }
26478-            return result;
26479-        },
26480-        logicMatch: function (type, exp1, exp2) {
26481-            var result;
26482-            switch (type) {
26483-                case '=':
26484-                    result = (exp1 === exp2);
26485-                    break;
26486-                case '>':
26487-                    result = (exp1 > exp2);
26488-                    break;
26489-                case '<':
26490-                    result = (exp1 < exp2);
26491-                    break;
26492-                case '>=':
26493-                    result = (exp1 >= exp2);
26494-                    break;
26495-                case '<=':
26496-                    result = (exp1 === exp2);
26497-                    break;
26498-                case '<>':
26499-                    result = (exp1 != exp2);
26500-                    break;
26501-                case 'NOT':
26502-                    result = (exp1 != exp2);
26503-                    break;
26504-            }
26505-            return result;
26506-        },
26507-        mathMatch: function (type, number1, number2) {
26508-            var result;
26509-            number1 = helper.number(number1);
26510-            number2 = helper.number(number2);
26511-            if (isNaN(number1) || isNaN(number2)) {
26512-                throw Error('VALUE');
26513-            }
26514-            switch (type) {
26515-                case '+':
26516-                    result = number1 + number2;
26517-                    break;
26518-                case '-':
26519-                    result = number1 - number2;
26520-                    break;
26521-                case '/':
26522-                    result = number1 / number2;
26523-                    if (result == Infinity) {
26524-                        throw Error('DIV_ZERO');
26525-                    }
26526-                    else if (isNaN(result)) {
26527-                        throw Error('VALUE');
26528-                    }
26529-                    break;
26530-                case '*':
26531-                    result = number1 * number2;
26532-                    break;
26533-                case '^':
26534-                    result = Math.pow(number1, number2);
26535-                    break;
26536-            }
26537-            return result;
26538-        },
26539-        callFunction: function (fn, args) {
26540-            fn = fn.toUpperCase();
26541-            args = args || [];
26542-            if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
26543-                if (Formula[fn]) {
26544-                    return Formula[fn].apply(this, args);
26545-                }
26546-            }
26547-            throw Error('NAME');
26548-        },
26549-        callVariable: function (args) {
26550-            args = args || [];
26551-            var str = args[0];
26552-            if (str) {
26553-                str = str.toUpperCase();
26554-                if (Formula[str]) {
26555-                    return ((typeof Formula[str] === 'function') ? Formula[str].apply(this, args) : Formula[str]);
26556-                }
26557-            }
26558-            throw Error('NAME');
26559-        },
26560-        cellValue: function (cell) {
26561-            var value, origin = this, item = instance.matrix.getItem(new A1CellKey(cell));
26562-            // get value
26563-            value = item ? item.value : "0"; // TODO: fix this, it's sloppy.
26564-            //update dependencies
26565-            // instance.matrix.updateCellItem(new A1CellKey(origin), {deps: [cell]});
26566-            instance.matrix.getItem(new A1CellKey(origin)).updateDependencies([cell]);
26567-            // check references error
26568-            if (item && item.deps) {
26569-                if (item.deps.indexOf(cell) !== -1) {
26570-                    throw Error('REF');
26571-                }
26572-            }
26573-            // check if any error occurs
26574-            if (item && item.error) {
26575-                throw Error(item.error);
26576-            }
26577-            // return value if is set
26578-            if (instance.utils.isSet(value)) {
26579-                var result = instance.helper.number(value);
26580-                return !isNaN(result) ? result : value;
26581-            }
26582-            // cell is not available
26583-            throw Error('NOT_AVAILABLE');
26584-        },
26585-        cellRangeValue: function (start, end) {
26586-            var coordsStart = instance.utils.cellCoords(start), coordsEnd = instance.utils.cellCoords(end), origin = this;
26587-            // iterate cells to get values and indexes
26588-            var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd), result = [];
26589-            //update dependencies
26590-            // instance.matrix.updateCellItem(new A1CellKey(origin), {deps: cells.index});
26591-            instance.matrix.getItem(new A1CellKey(origin)).updateDependencies([cells.index]);
26592-            result.push(cells.value);
26593-            return result;
26594-        },
26595-        fixedCellValue: function (id) {
26596-            id = id.replace(/\$/g, '');
26597-            return instance.helper.cellValue.call(this, id);
26598-        },
26599-        fixedCellRangeValue: function (start, end) {
26600-            start = start.replace(/\$/g, '');
26601-            end = end.replace(/\$/g, '');
26602-            return instance.helper.cellRangeValue.call(this, start, end);
26603-        }
26604-    };
26605-    var parse = function (formula, key) {
26606-        var result = null;
26607-        var error = null;
26608-        try {
26609-            parser.setObj(key);
26610-            result = parser.parse(formula);
26611-            var deps = instance.matrix.getDependencies(key);
26612-            if (deps.indexOf(key) !== -1) {
26613-                result = null;
26614-                deps.forEach(function (id) {
26615-                    // instance.matrix.updateItem(id, {value: null, error: Exception.get('REF')});
26616-                    instance.matrix.getItem(new A1CellKey(id)).setError(Exception.get('REF'));
26617-                    instance.matrix.getItem(new A1CellKey(id)).setValue(null);
26618-                });
26619-                throw Error('REF');
26620-            }
26621-        }
26622-        catch (ex) {
26623-            var message = Exception.get(ex.message);
26624-            if (message) {
26625-                error = message;
26626-            }
26627-            else {
26628-                error = Exception.get('ERROR');
26629-            }
26630-        }
26631-        return {
26632-            error: error,
26633-            result: result
26634-        };
26635-    };
26636-    var init = function () {
26637-        instance = this;
26638-        parser = FormulaParser(instance);
26639-        instance.matrix = new Matrix();
26640-        instance.matrix.scan();
26641-    };
26642-    return {
26643-        init: init,
26644-        utils: utils,
26645-        helper: helper,
26646-        parse: parse
26647-    };
26648-});
26649diff --git a/tsconfig.json b/tsconfig.json
26650index 39a290d..f867366 100644
26651--- a/tsconfig.json
26652+++ b/tsconfig.json
26653@@ -3,9 +3,9 @@
26654     "allowJs": true,
26655     "allowUnreachableCode": true,
26656     "allowUnusedLabels": true,
26657-    "outDir": "ts"
26658+    "outDir": "output"
26659   },
26660   "files": [
26661-    "ts/sheet.ts"
26662+    "ts/main.ts"
26663   ]
26664 }