spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[npm prep] getting package ready for publishing
author
Ben Vogt <[email protected]>
date
2017-05-20 15:10:21
stats
28 file(s) changed, 7242 insertions(+), 33 deletions(-)
files
.gitignore
README.md
TODO.md
dist/Cell.js
dist/Errors.js
dist/Formulas.js
dist/Formulas/AllFormulas.js
dist/Formulas/Date.js
dist/Formulas/Engineering.js
dist/Formulas/Financial.js
dist/Formulas/Logical.js
dist/Formulas/Math.js
dist/Formulas/Statistical.js
dist/Formulas/Text.js
dist/Sheet.js
dist/Utilities/ArgsChecker.js
dist/Utilities/CriteriaFunctionFactory.js
dist/Utilities/DateRegExBuilder.js
dist/Utilities/Filter.js
dist/Utilities/MathHelpers.js
dist/Utilities/Serializer.js
dist/Utilities/TypeConverter.js
dist/parser.js
package.json
src/Main.ts
src/Sheet.ts
tests/SheetFormulaTest.ts
tsconfig.json
   1diff --git a/.gitignore b/.gitignore
   2index 00696b8..04c7580 100644
   3--- a/.gitignore
   4+++ b/.gitignore
   5@@ -7,7 +7,6 @@
   6 *.profi
   7 *.module-cache
   8 node_modules/
   9-dist/
  10 build/
  11 npm-debug.log
  12 output/
  13diff --git a/README.md b/README.md
  14index a798beb..20d7f9a 100644
  15--- a/README.md
  16+++ b/README.md
  17@@ -3,25 +3,74 @@ TypeScript/javascript spreadsheet.
  18 
  19 ## Usage
  20 
  21-### Example
  22+### Examples
  23 
  24+**Using a Sheet**
  25 ```javascript
  26+var Sheet = require("./dist/Sheet.js").Sheet;
  27 var sheet = new Sheet();
  28 sheet.setCell("A1", "10");
  29 sheet.setCell("A2", "14");
  30 sheet.setCell("A4", "10e2");
  31 sheet.setCell("A5", "99.1");
  32 sheet.setCell("B1", "=SUM(A1:A5)");
  33-console.log(sheet.getCell("B1").getValue()); // output: 1124
  34+sheet.getCell("B1").getValue(); // returns: 1123.1
  35 ```
  36 
  37-### Ranges
  38+**Using Formulas Directly**
  39+```javascript
  40+var Formulas = require("./dist/Sheet.js").AllFormulas;
  41+Formulas.SUM(1, 2, 3, [4, 5, 6], "7"); // returns: 28
  42+```
  43+
  44+For a full list of formulas, see [DOCS.md](DOCS.md)
  45+
  46+
  47+**Nested Formulas**
  48+```javascript
  49+sheet.setCell('A1', '=SIN(PI() / 2)')
  50+sheet.getCell("A1").getValue(); // returns: 1
  51+```
  52+
  53+**Date Conversion**
  54+```javascript
  55+sheet.setCell('A1', '=DATEDIF("1992-6-19", "1996-6-19", "Y")')
  56+sheet.getCell("A1").getValue(); // returns: 4
  57+```
  58+
  59+**Number Parsing**
  60+```javascript
  61+sheet.setCell('A1', '="10e1" + 44');
  62+sheet.getCell("A1").getValue(); // returns: 144
  63+
  64+sheet.setCell('A2', '="1,000,000" + 1');
  65+sheet.getCell("A2").getValue(); // returns: 1000001
  66+
  67+sheet.setCell('A3', '="-$10.00" + 0');
  68+sheet.getCell("A3").getValue(); // returns: -10
  69+
  70+sheet.setCell('A4', '=10% + 1');
  71+sheet.getCell("A4").getValue(); // returns: 1.1
  72+
  73+sheet.setCell('A5', '= 2 ^ 10');
  74+sheet.getCell("A5").getValue(); // returns: 1024
  75+```
  76+
  77+
  78+## Ranges
  79 
  80 In MS Excel, and Google Spreadsheets, literal ranges are denoted with opening and closing curly-brackets. E.g. "{1, 2, 3}". In this implementation however, literal ranges are denoted with opening and closing brackets. E.g. "[1, 2, 3]".
  81 
  82+```javascript
  83+// OK
  84+sheet.setCell('A1', '=SUM([1, 2, 3])');
  85+// NOT OK
  86+sheet.setCell('A1', '=SUM({1, 2, 3})');
  87+```
  88+
  89 
  90 ## Docs
  91-[Docs here](DOCS.md)
  92+See [DOCS.md](DOCS.md) for full list and documentation of all formulas available.
  93 
  94 
  95 ## Contributing
  96@@ -38,7 +87,7 @@ If you're adding a new formula, before you submit a pull request or push ensure
  97 6) Build DOCS.md with `npm run docs`.
  98 
  99 
 100-### Why?
 101+## Why?
 102 Near the end of 2016 I began to ask myself why I didn't know more about MS Excel and Google Spreadsheets. Why didn't I know more about the most popular programing language in the world? I began to reverse engineer Google Spreadsheets in particular, gaining a better understanding along the way.
 103 
 104 I chose TypeScript because, coming from Java, it is really nice to be able to see type errors, and catch them. I also just enjoy getting specific with my return types, even if the specifications for a spreadsheet treat type flexibly.
 105@@ -46,10 +95,10 @@ I chose TypeScript because, coming from Java, it is really nice to be able to se
 106 For the formula documentation, I tried to be at least -- if not more -- thorough as Google Spreadsheets.
 107 
 108 
 109-### License
 110+## License
 111 
 112 For this repository's code license, and related licenses, see LICENSES directory.
 113 
 114 
 115-### Acknowledgements
 116+## Acknowledgements
 117 This is largely a re-write of [Handsontable](https://github.com/handsontable)'s [https://github.com/handsontable/ruleJS](https://github.com/handsontable/ruleJS), and [https://github.com/sutoiku/formula.js/](https://github.com/sutoiku/formula.js/). The parser was derived from Handsontable's, and many of the formulas were created with FormulaJS's formulas as a reference point.
 118\ No newline at end of file
 119diff --git a/TODO.md b/TODO.md
 120index 54e290d..025b7e5 100644
 121--- a/TODO.md
 122+++ b/TODO.md
 123@@ -1,5 +1,4 @@
 124 # TODO
 125-Things I should do.
 126 
 127 
 128 ### Cells should have `formatAs` fields.
 129diff --git a/dist/Cell.js b/dist/Cell.js
 130new file mode 100644
 131index 0000000..58de5db
 132--- /dev/null
 133+++ b/dist/Cell.js
 134@@ -0,0 +1,155 @@
 135+"use strict";
 136+exports.__esModule = true;
 137+/**
 138+ * Cell represents a cell in the spreadsheet. It contains a nullable rawFormulaText, and a value, which is not nullable unless
 139+ * the parsing of the rawFormulaText results in an error.
 140+ */
 141+var Cell = (function () {
 142+    /**
 143+     * Creates an empty cell with an id.
 144+     * @param id key of the cell in A1-format.
 145+     */
 146+    function Cell(id) {
 147+        /**
 148+         * The raw formula text that can be parse, excluding the proceeding =
 149+         * E.g: SUM(A2:A4, 10)
 150+         */
 151+        this.rawFormulaText = null;
 152+        this.typedValue = null;
 153+        this.dependencies = [];
 154+        this.error = null;
 155+        var key = parseKey(id);
 156+        this.id = id;
 157+        this.row = key.y;
 158+        this.col = key.x;
 159+    }
 160+    /**
 161+     * Update this cell's dependencies, where `dependencies` is a unique list of A1-format cell IDs.
 162+     * @param dependencies to merge with existing dependencies.
 163+     */
 164+    Cell.prototype.updateDependencies = function (dependencies) {
 165+        for (var index in dependencies) {
 166+            if (this.dependencies.indexOf(dependencies[index]) === -1) {
 167+                this.dependencies.push(dependencies[index]);
 168+            }
 169+        }
 170+    };
 171+    /**
 172+     * Return a list of dependencies in A1-format cell IDs, in no particular order, but likely in order of occurrence in
 173+     * rawFormulaText.
 174+     * @returns {Array<string>} list of dependencies in A1-format
 175+     */
 176+    Cell.prototype.getDependencies = function () {
 177+        return this.dependencies;
 178+    };
 179+    /**
 180+     * Return the zero-indexed column number of this cell.
 181+     * @returns {number} column
 182+     */
 183+    Cell.prototype.getColumn = function () {
 184+        return this.col;
 185+    };
 186+    /**
 187+     * Return the zero-indexed row number of this cell.
 188+     * @returns {number} row
 189+     */
 190+    Cell.prototype.getRow = function () {
 191+        return this.row;
 192+    };
 193+    /**
 194+     * Get the A1-format ID of this cell.
 195+     * @returns {string} cell ID
 196+     */
 197+    Cell.prototype.getId = function () {
 198+        return this.id;
 199+    };
 200+    /**
 201+     * Get the rawFormulaText of this cell if set. Defaults to null, so should be used in combination with hasFormula().
 202+     * @returns {string} rawFormulaText of this cell, if set. Nullable.
 203+     */
 204+    Cell.prototype.getFormula = function () {
 205+        return this.rawFormulaText;
 206+    };
 207+    /**
 208+     * Returns true if this cell has a formula to be parsed.
 209+     * @returns {boolean}
 210+     */
 211+    Cell.prototype.hasFormula = function () {
 212+        return this.rawFormulaText !== null;
 213+    };
 214+    /**
 215+     * Set the value of this cell. If this cell has a primitive value (does not contain a rawFormulaText), it could be set to a
 216+     * value while the rawFormulaText field is still null.
 217+     * @param value to set
 218+     */
 219+    Cell.prototype.setValue = function (value) {
 220+        this.typedValue = value;
 221+    };
 222+    /**
 223+     * Sets the value or rawFormulaText for this cell. If the input begins with =, then it is considered to be a rawFormulaText. If it
 224+     * is not, then it is a value, and set as the raw value for this cell.
 225+     * @param rawFormula
 226+     */
 227+    Cell.prototype.setRawValue = function (rawFormula) {
 228+        if (rawFormula.charAt(0) === "=") {
 229+            this.rawFormulaText = rawFormula.substr(1);
 230+        }
 231+        else {
 232+            this.typedValue = rawFormula;
 233+        }
 234+    };
 235+    /**
 236+     * Get the value of this cell. Since value could be null do to an error in the rawFormulaText, this could return null.
 237+     * @returns {any}
 238+     */
 239+    Cell.prototype.getValue = function () {
 240+        return this.typedValue;
 241+    };
 242+    /**
 243+     * CLears a cells value.
 244+     */
 245+    Cell.prototype.clearValue = function () {
 246+        this.typedValue = null;
 247+    };
 248+    /**
 249+     * Set error for this cell. Usually in the case of a parse error when parsing the rawFormulaText.
 250+     * @param error to set.
 251+     */
 252+    Cell.prototype.setError = function (error) {
 253+        this.error = error;
 254+    };
 255+    /**
 256+     * Get the error for this cell. If the rawFormulaText is not parsed properly, or is null, this could be null.
 257+     * @returns {Error} error to return, could be null.
 258+     */
 259+    Cell.prototype.getError = function () {
 260+        return this.error;
 261+    };
 262+    /**
 263+     * Returns the human-readable string representation of this cell, omitting some obvious fields.
 264+     * @returns {string}
 265+     */
 266+    Cell.prototype.toString = function () {
 267+        return "id=" + this.id + ", value=" + this.typedValue + ", rawFormulaText=" + this.rawFormulaText + ", error=" + this.error;
 268+    };
 269+    return Cell;
 270+}());
 271+exports.Cell = Cell;
 272+function toNum(chr) {
 273+    chr = chr.replace(/\$/g, '');
 274+    var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
 275+    for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
 276+        result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
 277+    }
 278+    if (result) {
 279+        --result;
 280+    }
 281+    return result;
 282+}
 283+function parseKey(cell) {
 284+    var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
 285+    return {
 286+        x: toNum(alpha),
 287+        y: parseInt(num[0], 10) - 1
 288+    };
 289+}
 290diff --git a/dist/Errors.js b/dist/Errors.js
 291new file mode 100644
 292index 0000000..1123f4a
 293--- /dev/null
 294+++ b/dist/Errors.js
 295@@ -0,0 +1,96 @@
 296+"use strict";
 297+var __extends = (this && this.__extends) || (function () {
 298+    var extendStatics = Object.setPrototypeOf ||
 299+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
 300+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
 301+    return function (d, b) {
 302+        extendStatics(d, b);
 303+        function __() { this.constructor = d; }
 304+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
 305+    };
 306+})();
 307+exports.__esModule = true;
 308+var NULL_ERROR = "#NULL!";
 309+exports.NULL_ERROR = NULL_ERROR;
 310+var DIV_ZERO_ERROR = "#DIV/0!";
 311+exports.DIV_ZERO_ERROR = DIV_ZERO_ERROR;
 312+var VALUE_ERROR = "#VALUE!";
 313+exports.VALUE_ERROR = VALUE_ERROR;
 314+var REF_ERROR = "#REF!";
 315+exports.REF_ERROR = REF_ERROR;
 316+var NAME_ERROR = "#NAME!";
 317+exports.NAME_ERROR = NAME_ERROR;
 318+var NUM_ERROR = "#NUM!";
 319+exports.NUM_ERROR = NUM_ERROR;
 320+var NA_ERROR = "#N/A";
 321+exports.NA_ERROR = NA_ERROR;
 322+var NullError = (function (_super) {
 323+    __extends(NullError, _super);
 324+    function NullError(message) {
 325+        var _this = _super.call(this, message) || this;
 326+        _this.name = NULL_ERROR;
 327+        return _this;
 328+    }
 329+    return NullError;
 330+}(Error));
 331+exports.NullError = NullError;
 332+var DivZeroError = (function (_super) {
 333+    __extends(DivZeroError, _super);
 334+    function DivZeroError(message) {
 335+        var _this = _super.call(this, message) || this;
 336+        _this.name = DIV_ZERO_ERROR;
 337+        return _this;
 338+    }
 339+    return DivZeroError;
 340+}(Error));
 341+exports.DivZeroError = DivZeroError;
 342+var ValueError = (function (_super) {
 343+    __extends(ValueError, _super);
 344+    function ValueError(message) {
 345+        var _this = _super.call(this, message) || this;
 346+        _this.name = VALUE_ERROR;
 347+        return _this;
 348+    }
 349+    return ValueError;
 350+}(Error));
 351+exports.ValueError = ValueError;
 352+var RefError = (function (_super) {
 353+    __extends(RefError, _super);
 354+    function RefError(message) {
 355+        var _this = _super.call(this, message) || this;
 356+        _this.name = REF_ERROR;
 357+        return _this;
 358+    }
 359+    return RefError;
 360+}(Error));
 361+exports.RefError = RefError;
 362+var NameError = (function (_super) {
 363+    __extends(NameError, _super);
 364+    function NameError(message) {
 365+        var _this = _super.call(this, message) || this;
 366+        _this.name = NAME_ERROR;
 367+        return _this;
 368+    }
 369+    return NameError;
 370+}(Error));
 371+exports.NameError = NameError;
 372+var NumError = (function (_super) {
 373+    __extends(NumError, _super);
 374+    function NumError(message) {
 375+        var _this = _super.call(this, message) || this;
 376+        _this.name = NUM_ERROR;
 377+        return _this;
 378+    }
 379+    return NumError;
 380+}(Error));
 381+exports.NumError = NumError;
 382+var NAError = (function (_super) {
 383+    __extends(NAError, _super);
 384+    function NAError(message) {
 385+        var _this = _super.call(this, message) || this;
 386+        _this.name = NA_ERROR;
 387+        return _this;
 388+    }
 389+    return NAError;
 390+}(Error));
 391+exports.NAError = NAError;
 392diff --git a/dist/Formulas.js b/dist/Formulas.js
 393new file mode 100644
 394index 0000000..630ae31
 395--- /dev/null
 396+++ b/dist/Formulas.js
 397@@ -0,0 +1,17 @@
 398+"use strict";
 399+exports.__esModule = true;
 400+var AllFormulas = require("./Formulas/AllFormulas");
 401+var Formulas = {
 402+    exists: function (fn) {
 403+        return ((fn in AllFormulas) || (fn in AllFormulas.__COMPLEX));
 404+    },
 405+    get: function (fn) {
 406+        if (fn in AllFormulas) {
 407+            return AllFormulas[fn];
 408+        }
 409+        if (fn in AllFormulas.__COMPLEX) {
 410+            return AllFormulas.__COMPLEX[fn];
 411+        }
 412+    }
 413+};
 414+exports.Formulas = Formulas;
 415diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 416new file mode 100644
 417index 0000000..8fc555c
 418--- /dev/null
 419+++ b/dist/Formulas/AllFormulas.js
 420@@ -0,0 +1,138 @@
 421+"use strict";
 422+exports.__esModule = true;
 423+var Math_1 = require("./Math");
 424+exports.ABS = Math_1.ABS;
 425+exports.ACOS = Math_1.ACOS;
 426+exports.ACOSH = Math_1.ACOSH;
 427+exports.ACOTH = Math_1.ACOTH;
 428+exports.ASIN = Math_1.ASIN;
 429+exports.ASINH = Math_1.ASINH;
 430+exports.ATAN = Math_1.ATAN;
 431+exports.ATAN2 = Math_1.ATAN2;
 432+exports.ATANH = Math_1.ATANH;
 433+exports.COT = Math_1.COT;
 434+exports.COTH = Math_1.COTH;
 435+exports.COSH = Math_1.COSH;
 436+exports.COS = Math_1.COS;
 437+exports.COUNTUNIQUE = Math_1.COUNTUNIQUE;
 438+exports.EVEN = Math_1.EVEN;
 439+exports.ERF = Math_1.ERF;
 440+exports.ERFC = Math_1.ERFC;
 441+exports.INT = Math_1.INT;
 442+exports.ISEVEN = Math_1.ISEVEN;
 443+exports.ISODD = Math_1.ISODD;
 444+exports.MOD = Math_1.MOD;
 445+exports.ODD = Math_1.ODD;
 446+exports.SIN = Math_1.SIN;
 447+exports.SINH = Math_1.SINH;
 448+exports.SUM = Math_1.SUM;
 449+exports.SQRT = Math_1.SQRT;
 450+exports.SQRTPI = Math_1.SQRTPI;
 451+exports.PI = Math_1.PI;
 452+exports.POWER = Math_1.POWER;
 453+exports.LOG = Math_1.LOG;
 454+exports.LOG10 = Math_1.LOG10;
 455+exports.LN = Math_1.LN;
 456+exports.TAN = Math_1.TAN;
 457+exports.TANH = Math_1.TANH;
 458+exports.ROUND = Math_1.ROUND;
 459+exports.ROUNDDOWN = Math_1.ROUNDDOWN;
 460+exports.ROUNDUP = Math_1.ROUNDUP;
 461+exports.SUMPRODUCT = Math_1.SUMPRODUCT;
 462+exports.SUMIF = Math_1.SUMIF;
 463+exports.SUMSQ = Math_1.SUMSQ;
 464+exports.SUMX2MY2 = Math_1.SUMX2MY2;
 465+exports.SUMX2PY2 = Math_1.SUMX2PY2;
 466+exports.FLOOR = Math_1.FLOOR;
 467+exports.IF = Math_1.IF;
 468+exports.COUNTIF = Math_1.COUNTIF;
 469+exports.COUNTIFS = Math_1.COUNTIFS;
 470+exports.CEILING = Math_1.CEILING;
 471+exports.TRUNC = Math_1.TRUNC;
 472+exports.RADIANS = Math_1.RADIANS;
 473+exports.DEGREES = Math_1.DEGREES;
 474+exports.COMBIN = Math_1.COMBIN;
 475+var Logical_1 = require("./Logical");
 476+exports.AND = Logical_1.AND;
 477+exports.EXACT = Logical_1.EXACT;
 478+exports.TRUE = Logical_1.TRUE;
 479+exports.FALSE = Logical_1.FALSE;
 480+exports.NOT = Logical_1.NOT;
 481+exports.OR = Logical_1.OR;
 482+exports.XOR = Logical_1.XOR;
 483+var Engineering_1 = require("./Engineering");
 484+exports.BIN2DEC = Engineering_1.BIN2DEC;
 485+exports.BIN2HEX = Engineering_1.BIN2HEX;
 486+exports.BIN2OCT = Engineering_1.BIN2OCT;
 487+exports.DEC2BIN = Engineering_1.DEC2BIN;
 488+exports.DEC2HEX = Engineering_1.DEC2HEX;
 489+exports.DEC2OCT = Engineering_1.DEC2OCT;
 490+exports.DELTA = Engineering_1.DELTA;
 491+var Financial_1 = require("./Financial");
 492+exports.ACCRINT = Financial_1.ACCRINT;
 493+exports.CUMPRINC = Financial_1.CUMPRINC;
 494+exports.CUMIPMT = Financial_1.CUMIPMT;
 495+exports.DB = Financial_1.DB;
 496+exports.DDB = Financial_1.DDB;
 497+exports.DOLLAR = Financial_1.DOLLAR;
 498+exports.DOLLARDE = Financial_1.DOLLARDE;
 499+exports.DOLLARFR = Financial_1.DOLLARFR;
 500+exports.EFFECT = Financial_1.EFFECT;
 501+var Statistical_1 = require("./Statistical");
 502+exports.AVERAGE = Statistical_1.AVERAGE;
 503+exports.AVERAGEA = Statistical_1.AVERAGEA;
 504+exports.AVERAGEIF = Statistical_1.AVERAGEIF;
 505+exports.AVEDEV = Statistical_1.AVEDEV;
 506+exports.CORREL = Statistical_1.CORREL;
 507+exports.COUNT = Statistical_1.COUNT;
 508+exports.COUNTA = Statistical_1.COUNTA;
 509+exports.PEARSON = Statistical_1.PEARSON;
 510+exports.MEDIAN = Statistical_1.MEDIAN;
 511+exports.DEVSQ = Statistical_1.DEVSQ;
 512+exports.EXPONDIST = Statistical_1.EXPONDIST;
 513+exports.FINV = Statistical_1.FINV;
 514+exports.FISHER = Statistical_1.FISHER;
 515+exports.FISHERINV = Statistical_1.FISHERINV;
 516+exports.MAX = Statistical_1.MAX;
 517+exports.MAXA = Statistical_1.MAXA;
 518+exports.MIN = Statistical_1.MIN;
 519+exports.MINA = Statistical_1.MINA;
 520+var Text_1 = require("./Text");
 521+exports.ARABIC = Text_1.ARABIC;
 522+exports.CHAR = Text_1.CHAR;
 523+exports.CODE = Text_1.CODE;
 524+exports.SPLIT = Text_1.SPLIT;
 525+exports.CONCATENATE = Text_1.CONCATENATE;
 526+exports.CONVERT = Text_1.CONVERT;
 527+var Date_1 = require("./Date");
 528+exports.DATE = Date_1.DATE;
 529+exports.DATEVALUE = Date_1.DATEVALUE;
 530+exports.DATEDIF = Date_1.DATEDIF;
 531+exports.DAYS = Date_1.DAYS;
 532+exports.DAY = Date_1.DAY;
 533+exports.DAYS360 = Date_1.DAYS360;
 534+exports.EDATE = Date_1.EDATE;
 535+exports.EOMONTH = Date_1.EOMONTH;
 536+exports.MONTH = Date_1.MONTH;
 537+exports.YEAR = Date_1.YEAR;
 538+exports.WEEKDAY = Date_1.WEEKDAY;
 539+exports.WEEKNUM = Date_1.WEEKNUM;
 540+exports.YEARFRAC = Date_1.YEARFRAC;
 541+exports.TIMEVALUE = Date_1.TIMEVALUE;
 542+exports.HOUR = Date_1.HOUR;
 543+exports.MINUTE = Date_1.MINUTE;
 544+exports.SECOND = Date_1.SECOND;
 545+exports.NETWORKDAYS = Date_1.NETWORKDAYS;
 546+exports.NETWORKDAYS$INTL = Date_1.NETWORKDAYS$INTL;
 547+exports.NOW = Date_1.NOW;
 548+exports.TODAY = Date_1.TODAY;
 549+exports.TIME = Date_1.TIME;
 550+exports.WORKDAY = Date_1.WORKDAY;
 551+exports.WORKDAY$INTL = Date_1.WORKDAY$INTL;
 552+// Using alias to bind dot-notation function names.
 553+var __COMPLEX = {
 554+    "F.DIST": Statistical_1.FDIST$LEFTTAILED,
 555+    "NETWORKDAYS.INTL": Date_1.NETWORKDAYS$INTL,
 556+    "WORKDAY.INTL": Date_1.WORKDAY$INTL
 557+};
 558+exports.__COMPLEX = __COMPLEX;
 559diff --git a/dist/Formulas/Date.js b/dist/Formulas/Date.js
 560new file mode 100644
 561index 0000000..bbbfdd2
 562--- /dev/null
 563+++ b/dist/Formulas/Date.js
 564@@ -0,0 +1,953 @@
 565+"use strict";
 566+exports.__esModule = true;
 567+/// <reference path="../../node_modules/moment/moment.d.ts"/>
 568+var moment = require("moment");
 569+var ArgsChecker_1 = require("../Utilities/ArgsChecker");
 570+var TypeConverter_1 = require("../Utilities/TypeConverter");
 571+var Errors_1 = require("../Errors");
 572+/**
 573+ * Converts a provided year, month, and day into a date.
 574+ * @param year - The year component of the date.
 575+ * @param month - The month component of the date.
 576+ * @param day - The day component of the date.
 577+ * @returns {number} newly created date.
 578+ * @constructor
 579+ */
 580+var DATE = function (year, month, day) {
 581+    var FIRST_YEAR = 1900;
 582+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "DATE");
 583+    year = Math.abs(Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(year))); // No negative values for year
 584+    month = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(month)) - 1; // Months are between 0 and 11.
 585+    day = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(day)) - 1; // Days are also zero-indexed.
 586+    var m = moment.utc(TypeConverter_1.TypeConverter.ORIGIN_MOMENT)
 587+        .add(2, "days")
 588+        .add(year < FIRST_YEAR ? year : year - FIRST_YEAR, 'years') // If the value is less than 1900, assume 1900 as start index for year
 589+        .add(month, 'months')
 590+        .add(day, 'days');
 591+    var dateAsNumber = TypeConverter_1.TypeConverter.momentToDayNumber(m);
 592+    if (dateAsNumber < 0) {
 593+        throw new Errors_1.NumError("DATE evaluates to an out of range value " + dateAsNumber
 594+            + ". It should be greater than or equal to 0.");
 595+    }
 596+    return dateAsNumber;
 597+};
 598+exports.DATE = DATE;
 599+/**
 600+ * Converts a provided date string in a known format to a date value.
 601+ * @param dateString - The string representing the date. Understood formats include any date format which is
 602+ * normally auto-converted when entered, without quotation marks, directly into a cell. Understood formats may depend on
 603+ * region and language settings.
 604+ * @returns {number} of days since 1900/1/1, inclusively.
 605+ * @constructor
 606+ */
 607+var DATEVALUE = function (dateString) {
 608+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "DATEVALUE");
 609+    dateString = TypeConverter_1.TypeConverter.firstValueAsString(dateString);
 610+    var dateAsNumber;
 611+    try {
 612+        dateAsNumber = TypeConverter_1.TypeConverter.stringToDateNumber(dateString);
 613+    }
 614+    catch (e) {
 615+        throw new Errors_1.ValueError("DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
 616+    }
 617+    // If we've not been able to parse the date by now, then we cannot parse it at all.
 618+    return dateAsNumber;
 619+};
 620+exports.DATEVALUE = DATEVALUE;
 621+/**
 622+ * Returns a date a specified number of months before or after another date.
 623+ * @param startDate - The date from which to calculate the result.
 624+ * @param months - The number of months before (negative) or after (positive) start_date to calculate.
 625+ * @returns {number} date a specified number of months before or after another date
 626+ * @constructor
 627+ */
 628+var EDATE = function (startDate, months) {
 629+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "EDATE");
 630+    var startDateNumber = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true); // tell firstValueAsDateNumber to coerce boolean
 631+    if (startDateNumber < 0) {
 632+        throw new Errors_1.NumError("Function EDATE parameter 1 value is " + startDateNumber + ". It should be greater than or equal to 0.");
 633+    }
 634+    months = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(months));
 635+    // While momentToDayNumber will return an inclusive count of days since 1900/1/1, moment.Moment.add assumes exclusive
 636+    // count of days.
 637+    return TypeConverter_1.TypeConverter.momentToDayNumber(moment.utc(TypeConverter_1.TypeConverter.ORIGIN_MOMENT).add(startDateNumber, "days").add(months, "months"));
 638+};
 639+exports.EDATE = EDATE;
 640+/**
 641+ * Returns a date representing the last day of a month which falls a specified number of months before or after another
 642+ * date.
 643+ * @param startDate - The date from which to calculate the the result.
 644+ * @param months - The number of months before (negative) or after (positive) start_date to consider. The last
 645+ * calendar day of the calculated month is returned.
 646+ * @returns {number} the last day of a month
 647+ * @constructor
 648+ */
 649+var EOMONTH = function (startDate, months) {
 650+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "EOMONTH");
 651+    var startDateNumber = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true); // tell firstValueAsDateNumber to coerce boolean
 652+    if (startDateNumber < 0) {
 653+        throw new Errors_1.NumError("Function EOMONTH parameter 1 value is " + startDateNumber + ". It should be greater than or equal to 0.");
 654+    }
 655+    months = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(months));
 656+    return TypeConverter_1.TypeConverter.momentToDayNumber(moment.utc(TypeConverter_1.TypeConverter.ORIGIN_MOMENT)
 657+        .add(startDateNumber, "days")
 658+        .add(months, "months")
 659+        .endOf("month"));
 660+};
 661+exports.EOMONTH = EOMONTH;
 662+/**
 663+ * Returns the day of the month that a specific date falls on, in numeric format.
 664+ * @param date - The date from which to extract the day. Must be a reference to a cell containing a date, a
 665+ * function returning a date type, or a number.
 666+ * @returns {number} day of the month
 667+ * @constructor
 668+ */
 669+var DAY = function (date) {
 670+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "DAY");
 671+    date = TypeConverter_1.TypeConverter.firstValueAsDateNumber(date, true); // tell firstValueAsDateNumber to coerce boolean
 672+    if (date < 0) {
 673+        throw new Errors_1.NumError("Function DAY parameter 1 value is " + date + ". It should be greater than or equal to 0.");
 674+    }
 675+    return TypeConverter_1.TypeConverter.numberToMoment(date).date();
 676+};
 677+exports.DAY = DAY;
 678+/**
 679+ * Returns the number of days between two dates.
 680+ * @param endDate most recently occurring
 681+ * @param startDate not most recently occurring
 682+ * @returns {number} of days between start_date and end_date
 683+ * @constructor
 684+ */
 685+var DAYS = function (endDate, startDate) {
 686+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "DAYS");
 687+    endDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(endDate, true); // tell firstValueAsDateNumber to coerce boolean
 688+    startDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true); // tell firstValueAsDateNumber to coerce boolean
 689+    return endDate - startDate;
 690+};
 691+exports.DAYS = DAYS;
 692+/**
 693+ * Returns the difference between two days based on the 360 day year used in some financial interest calculations.
 694+ * @param startDate - The start date to consider in the calculation. Must be a reference to a cell containing
 695+ * a date, a function returning a date type, or a number.
 696+ * @param endDate - The end date to consider in the calculation. Must be a reference to a cell containing a
 697+ * date, a function returning a date type, or a number.
 698+ * @param methodToUse - [ OPTIONAL - 0 by default ] - An indicator of what day count method to use.
 699+ * 0 indicates the US method - Under the US method, if start_date is the last day of a month, the day of month of
 700+ * start_date is changed to 30 for the purposes of the calculation. Furthermore if end_date is the last day of a month
 701+ * and the day of the month of start_date is earlier than the 30th, end_date is changed to the first day of the month
 702+ * following end_date, otherwise the day of month of end_date is changed to 30.
 703+ * Any other value indicates the European method - Under the European method, any start_date or end_date that falls on
 704+ * the 31st of a month has its day of month changed to 30.
 705+ * @returns {number} of days between two dates
 706+ * @constructor
 707+ */
 708+var DAYS360 = function (startDate, endDate, methodToUse) {
 709+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "DAYS360");
 710+    startDate = TypeConverter_1.TypeConverter.numberToMoment(TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true)); // tell firstValueAsDateNumber to coerce boolean
 711+    endDate = TypeConverter_1.TypeConverter.numberToMoment(TypeConverter_1.TypeConverter.firstValueAsDateNumber(endDate, true)); // tell firstValueAsDateNumber to coerce boolean
 712+    methodToUse = methodToUse ? TypeConverter_1.TypeConverter.firstValueAsBoolean(methodToUse) : false;
 713+    var smd = 31;
 714+    var emd = 31;
 715+    var sd = startDate.date();
 716+    var ed = endDate.date();
 717+    if (methodToUse) {
 718+        sd = (sd === 31) ? 30 : sd;
 719+        ed = (ed === 31) ? 30 : ed;
 720+    }
 721+    else {
 722+        if (startDate.month() === 1) {
 723+            smd = startDate.daysInMonth();
 724+        }
 725+        if (endDate.month() === 1) {
 726+            emd = endDate.daysInMonth();
 727+        }
 728+        sd = (sd === smd) ? 30 : sd;
 729+        if (sd === 30 || sd === smd) {
 730+            ed = (ed === emd) ? 30 : ed;
 731+        }
 732+    }
 733+    return 360 * (endDate.year() - startDate.year()) + 30 * (endDate.month() - startDate.month()) + (ed - sd);
 734+};
 735+exports.DAYS360 = DAYS360;
 736+/**
 737+ * Returns the month of the year a specific date falls in, in numeric format.
 738+ * @param date - The date from which to extract the month. Must be a reference to a cell containing a date, a
 739+ * function returning a date type, or a number.
 740+ * @returns {number} month of the year that the input date falls on.
 741+ * @constructor
 742+ */
 743+var MONTH = function (date) {
 744+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "MONTH");
 745+    date = TypeConverter_1.TypeConverter.firstValueAsDateNumber(date, true); // tell firstValueAsDateNumber to coerce boolean
 746+    if (date < 0) {
 747+        throw new Errors_1.NumError("Function MONTH parameter 1 value is " + date + ". It should be greater than or equal to 0.");
 748+    }
 749+    return TypeConverter_1.TypeConverter.numberToMoment(date).month() + 1;
 750+};
 751+exports.MONTH = MONTH;
 752+/**
 753+ * Returns the year specified by a given date.
 754+ * @param date - The date from which to calculate the year. Must be a cell reference to a cell containing a
 755+ * date, a function returning a date type, or a number.
 756+ * @returns {number} year of the input date
 757+ * @constructor
 758+ */
 759+var YEAR = function (date) {
 760+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "YEAR");
 761+    date = TypeConverter_1.TypeConverter.firstValueAsDateNumber(date, true); // tell firstValueAsDateNumber to coerce boolean
 762+    if (date < 0) {
 763+        throw new Errors_1.NumError("Function YEAR parameter 1 value is " + date + ". It should be greater than or equal to 0.");
 764+    }
 765+    return TypeConverter_1.TypeConverter.numberToMoment(date).year();
 766+};
 767+exports.YEAR = YEAR;
 768+/**
 769+ * Returns a number representing the day of the week of the date provided.
 770+ * @param date - The date for which to determine the day of the week. Must be a reference to a cell containing
 771+ * a date, a function returning a date type, or a number.
 772+ * @param offsetType - [ OPTIONAL - 1 by default ] - A number indicating which numbering system to use to represent
 773+ * weekdays. By default counts starting with Sunday = 1. If type is 1, days are counted from Sunday and the value of
 774+ * Sunday is 1, therefore the value of Saturday is 7. If type is 2, days are counted from Monday and the value of Monday
 775+ * is 1, therefore the value of Sunday is 7. If type is 3, days are counted from Monday and the value of Monday is 0,
 776+ * therefore the value of Sunday is 6.
 777+ * @returns {number} day of week
 778+ * @constructor
 779+ */
 780+var WEEKDAY = function (date, offsetType) {
 781+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "WEEKDAY");
 782+    date = TypeConverter_1.TypeConverter.firstValueAsDateNumber(date, true); // tell firstValueAsDateNumber to coerce boolean
 783+    offsetType = offsetType ? TypeConverter_1.TypeConverter.firstValueAsNumber(offsetType) : 1;
 784+    if (date < 0) {
 785+        throw new Errors_1.NumError("Function WEEKDAY parameter 1 value is " + date + ". It should be greater than or equal to 0.");
 786+    }
 787+    var day = TypeConverter_1.TypeConverter.numberToMoment(date).day();
 788+    if (offsetType === 1) {
 789+        return day + 1;
 790+    }
 791+    else if (offsetType === 2) {
 792+        if (day === 0) {
 793+            return 7;
 794+        }
 795+        return day;
 796+    }
 797+    else if (offsetType === 3) {
 798+        if (day === 0) {
 799+            return 6;
 800+        }
 801+        return day - 1;
 802+    }
 803+    else {
 804+        throw new Errors_1.NumError("Function WEEKDAY parameter 2 value " + day + " is out of range.");
 805+    }
 806+};
 807+exports.WEEKDAY = WEEKDAY;
 808+/**
 809+ * Returns a number representing the week of the year where the provided date falls. When inputting the date, it is best
 810+ * to use the DATE function, as text values may return errors.
 811+ *
 812+ * Behind the scenes, there are two week numbering "systems" used for this function: System 1 - The first week of the
 813+ * year is considered to be the week containing January 1, which is numbered week 1. System 2 - The first week of the
 814+ * year is considered to be the week containing the first Thursday of the year, which is numbered as week 1. System 2 is
 815+ * the approach specified in ISO 8601, also known as the European system for numbering weeks.
 816+ *
 817+ * @param date - The date for which to determine the week number. Must be a reference to a cell containing a
 818+ * date, a function returning a date type, or a number.
 819+ * @param shiftType - [ OPTIONAL - default is 1 ] - A number representing the day that a week starts on as well as
 820+ * the system used for determining the first week of the year (1=Sunday, 2=Monday).
 821+ * @returns {number} representing week number of year.
 822+ * @constructor
 823+ */
 824+var WEEKNUM = function (date, shiftType) {
 825+    // Given a moment, an array of days of the week for shifting, will calculate the week number.
 826+    function calculateWeekNum(dm, shifterArray) {
 827+        var startOfYear = moment.utc(dm).startOf("year");
 828+        var weeksCount = 1;
 829+        var d = moment.utc(dm).startOf("year").add(6 - shifterArray[startOfYear.day()], "days");
 830+        while (d.isBefore(dm)) {
 831+            d.add(7, "days");
 832+            weeksCount++;
 833+        }
 834+        return weeksCount;
 835+    }
 836+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "WEEKNUM");
 837+    date = TypeConverter_1.TypeConverter.firstValueAsDateNumber(date, true); // tell firstValueAsDateNumber to coerce boolean
 838+    shiftType = shiftType ? TypeConverter_1.TypeConverter.firstValueAsNumber(shiftType) : 1;
 839+    if (date < 0) {
 840+        throw new Errors_1.NumError("Function YEAR parameter 1 value is " + date + ". It should be greater than or equal to 0.");
 841+    }
 842+    var dm = TypeConverter_1.TypeConverter.numberToMoment(date);
 843+    var week = dm.week();
 844+    var dayOfWeek = dm.day(); // between 1 and 7, inclusively
 845+    if (shiftType === 1) {
 846+        // If this weekYear is not the same as the year, then we're technically in "week 53"
 847+        // See https://momentjs.com/docs/#/get-set/week-year/ for more info.
 848+        if (dm.weekYear() !== dm.year()) {
 849+            week = dm.weeksInYear() + 1;
 850+        }
 851+        return week;
 852+    }
 853+    else if (shiftType === 2 || shiftType === 11) {
 854+        if (dm.weekYear() !== dm.year()) {
 855+            week = dm.weeksInYear() + 1;
 856+        }
 857+        if (dayOfWeek === 0) {
 858+            return week - 1;
 859+        }
 860+        return week;
 861+    }
 862+    else if (shiftType === 12) {
 863+        if (dm.weekYear() !== dm.year()) {
 864+            week = dm.weeksInYear() + 1;
 865+        }
 866+        if (dayOfWeek <= 1) {
 867+            return week - 1;
 868+        }
 869+        return week;
 870+    }
 871+    else if (shiftType === 13) {
 872+        if (dm.weekYear() !== dm.year()) {
 873+            week = dm.weeksInYear() + 1;
 874+        }
 875+        if (dayOfWeek <= 2) {
 876+            return week - 1;
 877+        }
 878+        return week;
 879+    }
 880+    else if (shiftType === 14) {
 881+        return calculateWeekNum(dm, [3, 4, 5, 6, 0, 1, 2]);
 882+    }
 883+    else if (shiftType === 15) {
 884+        return calculateWeekNum(dm, [2, 3, 4, 5, 6, 0, 1]);
 885+    }
 886+    else if (shiftType === 16) {
 887+        return calculateWeekNum(dm, [1, 2, 3, 4, 5, 6, 0]);
 888+    }
 889+    else if (shiftType === 17) {
 890+        return calculateWeekNum(dm, [0, 1, 2, 3, 4, 5, 6]);
 891+    }
 892+    else if (shiftType === 21) {
 893+        return dm.isoWeek();
 894+    }
 895+    else {
 896+        throw new Errors_1.NumError("Function WEEKNUM parameter 2 value " + shiftType + " is out of range.");
 897+    }
 898+};
 899+exports.WEEKNUM = WEEKNUM;
 900+/**
 901+ * Calculates the number of days, months, or years between two dates.
 902+ * @param startDate - The start date to consider in the calculation. Must be a reference to a cell containing
 903+ * a DATE, a function returning a DATE type, or a number.
 904+ * @param endDate - The end date to consider in the calculation. Must be a reference to a cell containing a
 905+ * DATE, a function returning a DATE type, or a number.
 906+ * @param unit - A text abbreviation for unit of time. For example,"M" for month. Accepted values are "Y": the
 907+ * number of whole years between start_date and end_date, "M": the number of whole months between start_date and
 908+ * end_date, "D": the number of days between start_date and end_date, "MD": the number of days between start_date and
 909+ * end_date after subtracting whole months, "YM": the number of whole months between start_date and end_date after
 910+ * subtracting whole years, "YD": the number of days between start_date and end_date, assuming start_date and end_date
 911+ * were no more than one year apart.
 912+ * @returns {number} number of days, months, or years between two dates.
 913+ * @constructor
 914+ */
 915+var DATEDIF = function (startDate, endDate, unit) {
 916+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "DATEDIF");
 917+    startDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true);
 918+    endDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(endDate, true);
 919+    unit = TypeConverter_1.TypeConverter.firstValueAsString(unit);
 920+    var unitClean = unit.toUpperCase();
 921+    var startMoment = TypeConverter_1.TypeConverter.numberToMoment(startDate);
 922+    var endMoment = TypeConverter_1.TypeConverter.numberToMoment(endDate);
 923+    if (startDate > endDate) {
 924+        throw new Errors_1.NumError("Function DATEDIF parameter 1 (" + startDate.toString() +
 925+            ") should be on or before Function DATEDIF parameter 2 (" + endDate.toString() + ").");
 926+    }
 927+    if (unitClean === "Y") {
 928+        return Math.floor(endMoment.diff(startMoment, "years"));
 929+    }
 930+    else if (unitClean === "M") {
 931+        return Math.floor(endMoment.diff(startMoment, "months"));
 932+    }
 933+    else if (unitClean === "D") {
 934+        return endDate - startDate;
 935+    }
 936+    else if (unitClean === "MD") {
 937+        var s = startMoment;
 938+        while (s.isBefore(endMoment)) {
 939+            s.add(1, "month");
 940+        }
 941+        s.subtract(1, "month");
 942+        var days = endMoment.diff(s, "days");
 943+        return s.date() === endMoment.date() ? 0 : days;
 944+    }
 945+    else if (unitClean === "YM") {
 946+        var s = startMoment;
 947+        while (s.isBefore(endMoment)) {
 948+            s.add(1, "year");
 949+        }
 950+        s.subtract(1, "year");
 951+        var months = Math.floor(endMoment.diff(s, "months"));
 952+        return months === 12 ? 0 : months;
 953+    }
 954+    else if (unitClean === "YD") {
 955+        var s = startMoment;
 956+        while (s.isBefore(endMoment)) {
 957+            s.add(1, "year");
 958+        }
 959+        s.subtract(1, "year");
 960+        var days = Math.floor(endMoment.diff(s, "days"));
 961+        return days >= 365 ? 0 : days;
 962+    }
 963+    else {
 964+        throw new Errors_1.NumError("Function DATEDIF parameter 3 value is " + unit +
 965+            ". It should be one of: 'Y', 'M', 'D', 'MD', 'YM', 'YD'.");
 966+    }
 967+};
 968+exports.DATEDIF = DATEDIF;
 969+/**
 970+ * Returns the number of years, including fractional years, between two dates using a specified day count convention.
 971+ *
 972+ * Further reading:
 973+ *
 974+ * * http://christian-fries.de/blog/files/2013-yearfrac.html
 975+ *
 976+ * * http://finmath.net/finmath-lib/
 977+ *
 978+ * @param startDate - The start date to consider in the calculation. Must be a reference to a cell
 979+ * containing a date, a function returning a date type, or a number.
 980+ * @param endDate - The end date to consider in the calculation. Must be a reference to a cell containing
 981+ * a date, a function returning a date type, or a number.
 982+ * @param dayCountConvention - [ OPTIONAL - 0 by default ] - An indicator of what day count method to
 983+ * use.
 984+ * @returns {number}the number of years, including fractional years, between two dates
 985+ * @constructor
 986+ */
 987+var YEARFRAC = function (startDate, endDate, dayCountConvention) {
 988+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "YEARFRAC");
 989+    startDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true);
 990+    endDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(endDate, true);
 991+    dayCountConvention = dayCountConvention ? TypeConverter_1.TypeConverter.firstValueAsNumber(dayCountConvention) : 0;
 992+    var s = TypeConverter_1.TypeConverter.numberToMoment(startDate);
 993+    var e = TypeConverter_1.TypeConverter.numberToMoment(endDate);
 994+    if (e.isBefore(s)) {
 995+        var me = moment.utc(e);
 996+        e = moment.utc(s);
 997+        s = me;
 998+    }
 999+    var syear = s.year();
1000+    var smonth = s.month();
1001+    var sday = s.date();
1002+    var eyear = e.year();
1003+    var emonth = e.month();
1004+    var eday = e.date();
1005+    var feb29Between = function (date1, date2) {
1006+        // Requires year2 == (year1 + 1) or year2 == year1
1007+        // Returns TRUE if February 29 is between the two dates (date1 may be February 29), with two possibilities:
1008+        // year1 is a leap year and date1 <= February 29 of year1
1009+        // year2 is a leap year and date2 > February 29 of year2
1010+        var mar1year1 = moment.utc(new Date(date1.year(), 2, 1));
1011+        if (moment.utc([date1.year()]).isLeapYear() && date1.diff(mar1year1) < 0 && date2.diff(mar1year1) >= 0) {
1012+            return true;
1013+        }
1014+        var mar1year2 = moment.utc(new Date(date2.year(), 2, 1));
1015+        if (moment.utc([date2.year()]).isLeapYear() && date2.diff(mar1year2) >= 0 && date1.diff(mar1year2) < 0) {
1016+            return true;
1017+        }
1018+        return false;
1019+    };
1020+    switch (dayCountConvention) {
1021+        // US (NASD) 30/360
1022+        case 0:
1023+            // Note: if eday == 31, it stays 31 if sday < 30
1024+            if (sday === 31 && eday === 31) {
1025+                sday = 30;
1026+                eday = 30;
1027+            }
1028+            else if (sday === 31) {
1029+                sday = 30;
1030+            }
1031+            else if (sday === 30 && eday === 31) {
1032+                eday = 30;
1033+            }
1034+            else if (smonth === 1 && emonth === 1 && s.daysInMonth() === sday && e.daysInMonth() === eday) {
1035+                sday = 30;
1036+                eday = 30;
1037+            }
1038+            else if (smonth === 1 && s.daysInMonth() === sday) {
1039+                sday = 30;
1040+            }
1041+            return Math.abs(((eday + emonth * 30 + eyear * 360) - (sday + smonth * 30 + syear * 360)) / 360);
1042+        // Actual/actual
1043+        case 1:
1044+            var ylength = 365;
1045+            if (syear === eyear || ((syear + 1) === eyear) && ((smonth > emonth) || ((smonth === emonth) && (sday >= eday)))) {
1046+                if (syear === eyear && moment.utc([syear]).isLeapYear()) {
1047+                    ylength = 366;
1048+                }
1049+                else if (feb29Between(s, e) || (emonth === 1 && eday === 29)) {
1050+                    ylength = 366;
1051+                }
1052+                return Math.abs((endDate - startDate) / ylength);
1053+            }
1054+            else {
1055+                var years = (eyear - syear) + 1;
1056+                var days = moment.utc([eyear + 1]).startOf("year").diff(moment.utc([syear]).startOf("year"), 'days');
1057+                var average = days / years;
1058+                return Math.abs((endDate - startDate) / average);
1059+            }
1060+        // Actual/360
1061+        case 2:
1062+            return Math.abs(e.diff(s, 'days') / 360);
1063+        // Actual/365
1064+        case 3:
1065+            return Math.abs(e.diff(s, 'days') / 365);
1066+        // European 30/360
1067+        case 4:
1068+            sday = sday === 31 ? 30 : sday;
1069+            eday = eday === 31 ? 30 : eday;
1070+            // Remarkably, do NOT change February 28 or February 29 at ALL
1071+            return Math.abs(((eday + emonth * 30 + eyear * 360) - (sday + smonth * 30 + syear * 360)) / 360);
1072+    }
1073+    throw new Errors_1.NumError("Function YEARFRAC parameter 3 value is " + dayCountConvention + ". Valid values are between 0 and 4 inclusive.");
1074+};
1075+exports.YEARFRAC = YEARFRAC;
1076+/**
1077+ * Returns the fraction of a 24-hour day the time represents.
1078+ * @param timeString - The string that holds the time representation. Eg: "10am", "10:10", "10:10am", "10:10:11",
1079+ * or "10:10:11am".
1080+ * @returns {number} representing the fraction of a 24-hour day
1081+ * @constructor
1082+ */
1083+var TIMEVALUE = function (timeString) {
1084+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "TIMEVALUE");
1085+    timeString = TypeConverter_1.TypeConverter.firstValueAsString(timeString);
1086+    try {
1087+        return TypeConverter_1.TypeConverter.stringToTimeNumber(timeString);
1088+    }
1089+    catch (e) {
1090+        throw new Errors_1.ValueError("TIMEVALUE parameter '" + timeString + "' cannot be parsed to date/time.");
1091+    }
1092+};
1093+exports.TIMEVALUE = TIMEVALUE;
1094+var MILLISECONDS_IN_DAY = 86400000;
1095+/**
1096+ * Returns the hour component of a specific time, in numeric format.
1097+ * @param time - The time from which to calculate the hour component. Must be a reference to a cell containing
1098+ * a date/time, a function returning a date/time type, or a number.
1099+ * @returns {number}
1100+ * @constructor
1101+ */
1102+var HOUR = function (time) {
1103+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "HOUR");
1104+    time = TypeConverter_1.TypeConverter.firstValueAsTimestampNumber(time);
1105+    if (time % 1 === 0) {
1106+        return 0;
1107+    }
1108+    var m = moment.utc([1900]).add(time * MILLISECONDS_IN_DAY, "milliseconds");
1109+    return m.hour();
1110+};
1111+exports.HOUR = HOUR;
1112+/**
1113+ * Returns the minute component of a specific time, in numeric format.
1114+ * @param time - The time from which to calculate the minute component. Must be a reference to a cell
1115+ * containing a date/time, a function returning a date/time type, or a number.
1116+ * @returns {number} minute of the time passed in.
1117+ * @constructor
1118+ */
1119+var MINUTE = function (time) {
1120+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "MINUTE");
1121+    time = TypeConverter_1.TypeConverter.firstValueAsTimestampNumber(time);
1122+    if (time % 1 === 0) {
1123+        return 0;
1124+    }
1125+    var m = moment.utc([1900]).add(time * MILLISECONDS_IN_DAY, "milliseconds");
1126+    return m.minute();
1127+};
1128+exports.MINUTE = MINUTE;
1129+/**
1130+ * Returns the second component of a specific time, in numeric format.
1131+ * @param time - The time from which to calculate the second component. Must be a reference to a cell
1132+ * containing a date/time, a function returning a date/time type, or a number.
1133+ * @returns {number} second component of a specific time.
1134+ * @constructor
1135+ */
1136+var SECOND = function (time) {
1137+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "SECOND");
1138+    time = TypeConverter_1.TypeConverter.firstValueAsTimestampNumber(time);
1139+    if (time % 1 === 0) {
1140+        return 0;
1141+    }
1142+    var m = moment.utc([1900]).add(time * MILLISECONDS_IN_DAY, "milliseconds");
1143+    return m.second();
1144+};
1145+exports.SECOND = SECOND;
1146+/**
1147+ * Returns the number of net working days between two provided days.
1148+ * @param startDate - The start date of the period from which to calculate the number of net working days.
1149+ * @param endDate - The end date of the period from which to calculate the number of net working days.
1150+ * @param holidays - [ OPTIONAL ] - A range or array constant containing the date serial numbers to consider
1151+ * holidays. The values provided within an array for holidays must be date serial number values, as returned by N or
1152+ * date values, as returned by DATE, DATEVALUE or TO_DATE. Values specified by a range should be standard date values or
1153+ * date serial numbers.
1154+ * @returns {number} the number of net working days between two provided dates.
1155+ * @constructor
1156+ */
1157+var NETWORKDAYS = function (startDate, endDate, holidays) {
1158+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "NETWORKDAYS");
1159+    startDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true);
1160+    endDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(endDate, true);
1161+    var hasHolidays = (holidays !== undefined);
1162+    var cleanHolidays = [];
1163+    if (hasHolidays) {
1164+        holidays = (holidays instanceof Array) ? holidays : [holidays];
1165+        if (holidays.length === 0) {
1166+            throw new Errors_1.RefError("Reference does not exist.");
1167+        }
1168+        for (var _i = 0, holidays_1 = holidays; _i < holidays_1.length; _i++) {
1169+            var holidayDateValue = holidays_1[_i];
1170+            if (typeof holidayDateValue === "number") {
1171+                cleanHolidays.push(holidayDateValue);
1172+            }
1173+            else {
1174+                throw new Errors_1.ValueError("NETWORKDAYS expects number values. But '" + holidayDateValue + "' is a " +
1175+                    (typeof holidayDateValue) + " and cannot be coerced to a number.");
1176+            }
1177+        }
1178+    }
1179+    // Handle cases in which the start date is not before the end date.
1180+    var didSwap = startDate > endDate;
1181+    if (didSwap) {
1182+        var swap = endDate;
1183+        endDate = startDate;
1184+        startDate = swap;
1185+    }
1186+    var countMoment = moment.utc(TypeConverter_1.TypeConverter.numberToMoment(startDate));
1187+    var weekendDays = [6, 0]; // Default weekend_days.
1188+    var days = endDate - startDate + 1;
1189+    var networkDays = days;
1190+    var j = 0;
1191+    while (j < days) {
1192+        if (weekendDays.indexOf(countMoment.day()) >= 0) {
1193+            networkDays--;
1194+        }
1195+        else if (hasHolidays && cleanHolidays.indexOf(TypeConverter_1.TypeConverter.momentToDayNumber(countMoment)) > -1) {
1196+            networkDays--;
1197+        }
1198+        countMoment.add(1, 'days');
1199+        j++;
1200+    }
1201+    // If the we swapped the start and end date, the result should be a negative number of network days.
1202+    if (didSwap) {
1203+        return networkDays * -1;
1204+    }
1205+    return networkDays;
1206+};
1207+exports.NETWORKDAYS = NETWORKDAYS;
1208+/**
1209+ * Returns the number of networking days between two provided days excluding specified weekend days and holidays.
1210+ * @param startDate - The start date of the period from which to calculate the number of net working days.
1211+ * @param endDate - The end date of the period from which to calculate the number of net working days.
1212+ * @param weekend - [ OPTIONAL - 1 by default ] - A number or string representing which days of the week are
1213+ * considered weekends. String method: weekends can be specified using seven 0’s and 1’s, where the first number in the
1214+ * set represents Monday and the last number is for Sunday. A zero means that the day is a work day, a 1 means that the
1215+ * day is a weekend. For example, “0000011” would mean Saturday and Sunday are weekends. Number method: instead of using
1216+ * the string method above, a single number can be used. 1 = Saturday/Sunday are weekends, 2 = Sunday/Monday, and this
1217+ * pattern repeats until 7 = Friday/Saturday. 11 = Sunday is the only weekend, 12 = Monday is the only weekend, and this
1218+ * pattern repeats until 17 = Saturday is the only weekend.
1219+ * @param holidays - [ OPTIONAL ] - A range or array constant containing the dates to consider as holidays.
1220+ * The values provided within an array for holidays must be date serial number values, as returned by N or date values,
1221+ * as returned by DATE, DATEVALUE or TO_DATE. Values specified by a range should be standard date values or date serial
1222+ * numbers.
1223+ * @returns {number} of networking days between two provided days
1224+ * @constructor
1225+ */
1226+var NETWORKDAYS$INTL = function (startDate, endDate, weekend, holidays) {
1227+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 4, "NETWORKDAYS$INTL");
1228+    startDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true);
1229+    endDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(endDate, true);
1230+    var weekendDays = [];
1231+    if (weekend !== undefined) {
1232+        weekend = TypeConverter_1.TypeConverter.firstValue(weekend);
1233+        if (typeof weekend === "string") {
1234+            if (!/^[0-1]{6,}$/.test(weekend)) {
1235+                throw new Errors_1.NumError("Function NETWORKDAYS.INTL parameter 3 requires a number in the format '0000011'. "
1236+                    + "Actual value is '" + weekend + "'");
1237+            }
1238+            var ws = weekend.split("");
1239+            for (var i = 0; i < ws.length; i++) {
1240+                if (ws[i] === "1") {
1241+                    weekendDays.push(i === 6 ? 0 : i + 1);
1242+                }
1243+            }
1244+        }
1245+        else if (typeof weekend === "number") {
1246+            switch (weekend) {
1247+                case 1:
1248+                    weekendDays = [0, 6];
1249+                    break;
1250+                case 2:
1251+                case 3:
1252+                case 4:
1253+                case 5:
1254+                case 6:
1255+                case 7:
1256+                    weekendDays = [weekend, weekend - 1];
1257+                    break;
1258+                case 11:
1259+                case 12:
1260+                case 13:
1261+                case 14:
1262+                case 15:
1263+                case 16:
1264+                case 17:
1265+                    weekendDays = [weekend - 10];
1266+                    break;
1267+                default:
1268+                    throw new Errors_1.NumError("Function NETWORKDAYS.INTL parameter 3 requires a number in the range 1-7 or 11-17. "
1269+                        + "Actual number is " + weekend + ".");
1270+            }
1271+        }
1272+        else {
1273+            throw new Errors_1.ValueError("Function NETWORKDAYS.INTL parameter 4 expects number values. But '" + weekend
1274+                + "' cannot be coerced to a number.");
1275+        }
1276+    }
1277+    else {
1278+        weekendDays = [0, 6];
1279+    }
1280+    var hasHolidays = holidays !== undefined;
1281+    var cleanHolidays = [];
1282+    if (hasHolidays) {
1283+        if (holidays === 0) {
1284+            throw new Errors_1.RefError("Reference does not exist.");
1285+        }
1286+        for (var _i = 0, holidays_2 = holidays; _i < holidays_2.length; _i++) {
1287+            var holidayDateValue = holidays_2[_i];
1288+            if (typeof holidayDateValue === "number") {
1289+                cleanHolidays.push(holidayDateValue);
1290+            }
1291+            else {
1292+                throw new Errors_1.ValueError("NETWORKDAYS.INTL expects number values. But '" + holidayDateValue + "' is a " +
1293+                    (typeof holidayDateValue) + " and cannot be coerced to a number.");
1294+            }
1295+        }
1296+    }
1297+    // Handle cases in which the start date is not before the end date.
1298+    var didSwap = startDate > endDate;
1299+    if (didSwap) {
1300+        var swap = endDate;
1301+        endDate = startDate;
1302+        startDate = swap;
1303+    }
1304+    var countMoment = moment.utc(TypeConverter_1.TypeConverter.numberToMoment(startDate));
1305+    var days = endDate - startDate + 1;
1306+    var networkDays = days;
1307+    var j = 0;
1308+    while (j < days) {
1309+        if (weekendDays.indexOf(countMoment.day()) >= 0) {
1310+            networkDays--;
1311+        }
1312+        else if (hasHolidays && cleanHolidays.indexOf(TypeConverter_1.TypeConverter.momentToDayNumber(countMoment)) > -1) {
1313+            networkDays--;
1314+        }
1315+        countMoment.add(1, 'days');
1316+        j++;
1317+    }
1318+    // If the we swapped the start and end date, the result should be a negative number of network days.
1319+    if (didSwap) {
1320+        return networkDays * -1;
1321+    }
1322+    return networkDays;
1323+};
1324+exports.NETWORKDAYS$INTL = NETWORKDAYS$INTL;
1325+/**
1326+ * Returns the current date and time as a date value.
1327+ * @returns {number} representing the current date and time.
1328+ * @constructor
1329+ */
1330+var NOW = function () {
1331+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 0, "NOW");
1332+    return TypeConverter_1.TypeConverter.momentToNumber(moment.utc());
1333+};
1334+exports.NOW = NOW;
1335+/**
1336+ * Returns the current date as a date value.
1337+ * @returns {number} today
1338+ * @constructor
1339+ */
1340+var TODAY = function () {
1341+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 0, "TODAY");
1342+    return TypeConverter_1.TypeConverter.momentToNumber(moment.utc().startOf("day"));
1343+};
1344+exports.TODAY = TODAY;
1345+/**
1346+ * Converts a provided hour, minute, and second into a time. Will silently recalculate numeric time values which fall
1347+ * outside of valid ranges. Eg: TIME(24, 0, 0) is the same as TIME(0, 0, 0).
1348+ * @param hours - The hour component of the time.
1349+ * @param minutes - The minute component of the time.
1350+ * @param seconds - The second component of the time.
1351+ * @returns {number} time of day
1352+ * @constructor
1353+ */
1354+var TIME = function (hours, minutes, seconds) {
1355+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "TIME");
1356+    hours = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(hours));
1357+    minutes = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(minutes));
1358+    seconds = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(seconds));
1359+    var e = TypeConverter_1.TypeConverter.unitsToTimeNumber(hours, minutes, seconds);
1360+    if (e < 0) {
1361+        throw new Errors_1.NumError("TIME evaluates to an out of range value " + e + ". It should be greater than or equal to 0.");
1362+    }
1363+    return e;
1364+};
1365+exports.TIME = TIME;
1366+/**
1367+ * Calculates the end date after a specified number of working days.
1368+ * @param startDate - The date from which to begin counting.
1369+ * @param numberOfDays - The number of working days to advance from start_date. If negative, counts backwards. If
1370+ * not an integer, truncate.
1371+ * @param holidays - [ OPTIONAL ] - A range or array constant containing the dates to consider holidays. The
1372+ * values provided within an array for holidays must be date serial number values, as returned by N or date values, as
1373+ * returned by DATE, DATEVALUE or TO_DATE. Values specified by a range should be standard date values or date serial
1374+ * numbers.
1375+ * @returns {number} end date after a specified number of working days.
1376+ * @constructor
1377+ */
1378+var WORKDAY = function (startDate, numberOfDays, holidays) {
1379+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "WORKDAY");
1380+    startDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true);
1381+    numberOfDays = TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfDays);
1382+    var hasHolidays = (cleanHolidays !== undefined);
1383+    var cleanHolidays = [];
1384+    if (hasHolidays !== undefined) {
1385+        if (holidays instanceof Array) {
1386+            if (holidays.length === 0) {
1387+                throw new Errors_1.RefError("Reference does not exist.");
1388+            }
1389+            for (var _i = 0, holidays_3 = holidays; _i < holidays_3.length; _i++) {
1390+                var holidayDateValue = holidays_3[_i];
1391+                if (typeof holidayDateValue === "number") {
1392+                    cleanHolidays.push(holidayDateValue);
1393+                }
1394+                else {
1395+                    throw new Errors_1.ValueError("WORKDAY expects number values. But '" + holidayDateValue + "' is a " +
1396+                        (typeof holidayDateValue) + " and cannot be coerced to a number.");
1397+                }
1398+            }
1399+        }
1400+        else {
1401+            cleanHolidays.push(TypeConverter_1.TypeConverter.valueToNumber(holidays));
1402+        }
1403+    }
1404+    var weekendDays = [0, 6];
1405+    var countMoment = moment.utc(TypeConverter_1.TypeConverter.numberToMoment(startDate));
1406+    var j = 0;
1407+    while (j < numberOfDays) {
1408+        countMoment.add(1, 'days');
1409+        if (weekendDays.indexOf(countMoment.day()) < 0 && cleanHolidays.indexOf(TypeConverter_1.TypeConverter.momentToDayNumber(countMoment)) < 0) {
1410+            j++;
1411+        }
1412+    }
1413+    return TypeConverter_1.TypeConverter.momentToDayNumber(countMoment);
1414+};
1415+exports.WORKDAY = WORKDAY;
1416+/**
1417+ * Calculates the date after a specified number of workdays excluding specified weekend days and holidays.
1418+ * @param startDate - The date from which to begin counting.
1419+ * @param numberOfDays - The number of working days to advance from start_date. If negative, counts backwards.
1420+ * @param weekend - [ OPTIONAL - 1 by default ] - A number or string representing which days of the week are
1421+ * considered weekends. String method: weekends can be specified using seven 0’s and 1’s, where the first number in the
1422+ * set represents Monday and the last number is for Sunday. A zero means that the day is a work day, a 1 means that the
1423+ * day is a weekend. For example, “0000011” would mean Saturday and Sunday are weekends. Number method: instead of using
1424+ * the string method above, a single number can be used. 1 = Saturday/Sunday are weekends, 2 = Sunday/Monday, and this
1425+ * pattern repeats until 7 = Friday/Saturday. 11 = Sunday is the only weekend, 12 = Monday is the only weekend, and this
1426+ * pattern repeats until 17 = Saturday is the only weekend.
1427+ * @param holidays - [ OPTIONAL ] - A range or array constant containing the dates to consider holidays.
1428+ * @returns {number}
1429+ * @constructor
1430+ */
1431+var WORKDAY$INTL = function (startDate, numberOfDays, weekend, holidays) {
1432+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "WORKDAY$INTL");
1433+    startDate = TypeConverter_1.TypeConverter.firstValueAsDateNumber(startDate, true);
1434+    numberOfDays = TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfDays);
1435+    var weekendDays = [];
1436+    if (weekend !== undefined) {
1437+        weekend = TypeConverter_1.TypeConverter.firstValue(weekend);
1438+        if (typeof weekend === "string") {
1439+            if (!/^[0-1]{6,}$/.test(weekend)) {
1440+                throw new Errors_1.NumError("Function WORKDAY.INTL parameter 3 requires a number in the format '0000011'. "
1441+                    + "Actual value is '" + weekend + "'");
1442+            }
1443+            var ws = weekend.split("");
1444+            for (var i = 0; i < ws.length; i++) {
1445+                if (ws[i] === "1") {
1446+                    weekendDays.push(i === 6 ? 0 : i + 1);
1447+                }
1448+            }
1449+        }
1450+        else if (typeof weekend === "number") {
1451+            switch (weekend) {
1452+                case 1:
1453+                    weekendDays = [0, 6];
1454+                    break;
1455+                case 2:
1456+                case 3:
1457+                case 4:
1458+                case 5:
1459+                case 6:
1460+                case 7:
1461+                    weekendDays = [weekend, weekend - 1];
1462+                    break;
1463+                case 11:
1464+                case 12:
1465+                case 13:
1466+                case 14:
1467+                case 15:
1468+                case 16:
1469+                case 17:
1470+                    weekendDays = [weekend - 10];
1471+                    break;
1472+                default:
1473+                    throw new Errors_1.NumError("Function WORKDAY.INTL parameter 3 requires a number in the range 1-7 or 11-17. "
1474+                        + "Actual number is " + weekend + ".");
1475+            }
1476+        }
1477+        else {
1478+            throw new Errors_1.ValueError("Function WORKDAY.INTL parameter 4 expects number values. But '" + weekend
1479+                + "' cannot be coerced to a number.");
1480+        }
1481+    }
1482+    else {
1483+        weekendDays = [0, 6];
1484+    }
1485+    var hasHolidays = (holidays !== undefined);
1486+    var cleanHolidays = [];
1487+    if (hasHolidays) {
1488+        if (holidays instanceof Array) {
1489+            if (holidays.length === 0) {
1490+                throw new Errors_1.RefError("Reference does not exist.");
1491+            }
1492+            for (var _i = 0, holidays_4 = holidays; _i < holidays_4.length; _i++) {
1493+                var holidayDateValue = holidays_4[_i];
1494+                if (typeof holidayDateValue === "number") {
1495+                    cleanHolidays.push(holidayDateValue);
1496+                }
1497+                else {
1498+                    throw new Errors_1.ValueError("WORKDAY expects number values. But '" + holidayDateValue + "' is a " +
1499+                        (typeof holidayDateValue) + " and cannot be coerced to a number.");
1500+                }
1501+            }
1502+        }
1503+        else {
1504+            cleanHolidays.push(TypeConverter_1.TypeConverter.valueToNumber(holidays));
1505+        }
1506+    }
1507+    var countMoment = moment.utc(TypeConverter_1.TypeConverter.numberToMoment(startDate));
1508+    var j = 0;
1509+    while (j < numberOfDays) {
1510+        countMoment.add(1, 'days');
1511+        if (weekendDays.indexOf(countMoment.day()) < 0 && cleanHolidays.indexOf(TypeConverter_1.TypeConverter.momentToDayNumber(countMoment)) < 0) {
1512+            j++;
1513+        }
1514+    }
1515+    return TypeConverter_1.TypeConverter.momentToDayNumber(countMoment);
1516+};
1517+exports.WORKDAY$INTL = WORKDAY$INTL;
1518diff --git a/dist/Formulas/Engineering.js b/dist/Formulas/Engineering.js
1519new file mode 100644
1520index 0000000..32706c1
1521--- /dev/null
1522+++ b/dist/Formulas/Engineering.js
1523@@ -0,0 +1,288 @@
1524+"use strict";
1525+exports.__esModule = true;
1526+var ArgsChecker_1 = require("../Utilities/ArgsChecker");
1527+var TypeConverter_1 = require("../Utilities/TypeConverter");
1528+var Errors_1 = require("../Errors");
1529+/**
1530+ * Converts a signed binary number to decimal format.
1531+ * @param signedBinaryNumber - The signed 10-bit binary value to be converted to decimal, provided as a
1532+ * string. The most significant bit of signed_binary_number is the sign bit; that is, negative numbers are represented
1533+ * in two's complement format.
1534+ * @returns {number}
1535+ * @constructor
1536+ */
1537+var BIN2DEC = function (signedBinaryNumber) {
1538+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "BIN2DEC");
1539+    if (typeof TypeConverter_1.TypeConverter.firstValue(signedBinaryNumber) === "boolean") {
1540+        throw new Errors_1.ValueError("Function BIN2DEC parameter 1 expects text values. But '" + signedBinaryNumber + "' is a boolean and cannot be coerced to a text.");
1541+    }
1542+    var n = TypeConverter_1.TypeConverter.firstValueAsString(signedBinaryNumber);
1543+    if (!(/^[01]{1,10}$/).test(n)) {
1544+        throw new Errors_1.NumError("Input for BIN2DEC ('" + n + "') is not a valid binary representation.");
1545+    }
1546+    if (n.length === 10 && n.substring(0, 1) === '1') {
1547+        return parseInt(n.substring(1), 2) - 512;
1548+    }
1549+    return parseInt(n, 2);
1550+};
1551+exports.BIN2DEC = BIN2DEC;
1552+/**
1553+ * Converts a signed binary number to signed hexadecimal format.
1554+ * @param signedBinaryNumber - The signed 10-bit binary value to be converted to signed hexadecimal,
1555+ * provided as a string. The most significant bit of signed_binary_number is the sign bit; that is, negative numbers are
1556+ * represented in two's complement format.
1557+ * @param significantDigits - [ OPTIONAL ] - The number of significant digits to ensure in the result.
1558+ * @returns {string} string representation of a signed hexadecimal
1559+ * @constructor
1560+ */
1561+var BIN2HEX = function (signedBinaryNumber, significantDigits) {
1562+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "BIN2HEX");
1563+    if (typeof TypeConverter_1.TypeConverter.firstValue(signedBinaryNumber) === "boolean") {
1564+        throw new Errors_1.ValueError("Function BIN2HEX parameter 1 expects text values. But '" + signedBinaryNumber + "' is a boolean and cannot be coerced to a text.");
1565+    }
1566+    var n = TypeConverter_1.TypeConverter.firstValueAsString(signedBinaryNumber);
1567+    var p = 10;
1568+    if (significantDigits !== undefined) {
1569+        p = TypeConverter_1.TypeConverter.firstValueAsNumber(significantDigits);
1570+    }
1571+    if (!(/^[01]{1,10}$/).test(n)) {
1572+        throw new Errors_1.NumError("Input for BIN2HEX ('" + n + "') is not a valid binary representation.");
1573+    }
1574+    if (n.length === 10 && n.substring(0, 1) === '1') {
1575+        return (1099511627264 + parseInt(n.substring(1), 2)).toString(16).toUpperCase();
1576+    }
1577+    if (p < 1 || p > 10) {
1578+        throw new Errors_1.NumError("Function BIN2HEX parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
1579+    }
1580+    p = Math.floor(p);
1581+    // Convert decimal number to hexadecimal
1582+    var result = parseInt(n.toString(), 2).toString(16).toUpperCase();
1583+    if (p === 10) {
1584+        return result;
1585+    }
1586+    var str = "";
1587+    for (var i = 0; i < p - result.length; i++) {
1588+        str += "0";
1589+    }
1590+    return str + result;
1591+};
1592+exports.BIN2HEX = BIN2HEX;
1593+/**
1594+ * Converts a signed binary number to signed octal format.
1595+ * @param signedBinaryNumber - The signed 10-bit binary value to be converted to signed octal, provided as a
1596+ * string. The most significant bit of signed_binary_number is the sign bit; that is, negative numbers are represented
1597+ * in two's complement format.
1598+ * @param significantDigits - [ OPTIONAL ] - The number of significant digits to ensure in the result. If
1599+ * this is greater than the number of significant digits in the result, the result is left-padded with zeros until the
1600+ * total number of digits reaches significant_digits.
1601+ * @returns {string} number in octal format
1602+ * @constructor
1603+ */
1604+var BIN2OCT = function (signedBinaryNumber, significantDigits) {
1605+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "BIN2OCT");
1606+    if (typeof TypeConverter_1.TypeConverter.firstValue(signedBinaryNumber) === "boolean") {
1607+        throw new Errors_1.ValueError("Function BIN2OCT parameter 1 expects text values. But '" + signedBinaryNumber + "' is a boolean and cannot be coerced to a text.");
1608+    }
1609+    var n = TypeConverter_1.TypeConverter.firstValueAsString(signedBinaryNumber);
1610+    var p = 10;
1611+    if (significantDigits !== undefined) {
1612+        p = TypeConverter_1.TypeConverter.firstValueAsNumber(significantDigits);
1613+    }
1614+    if (!(/^[01]{1,10}$/).test(n)) {
1615+        throw new Errors_1.NumError("Input for BIN2OCT ('" + n + "') is not a valid binary representation.");
1616+    }
1617+    if (n.length === 10 && n.substring(0, 1) === '1') {
1618+        return (1073741312 + parseInt(n.substring(1), 2)).toString(8);
1619+    }
1620+    if (p < 1 || p > 10) {
1621+        throw new Errors_1.NumError("Function BIN2OCT parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
1622+    }
1623+    p = Math.floor(p);
1624+    var result = parseInt(n.toString(), 2).toString(8);
1625+    if (p === 10) {
1626+        return result;
1627+    }
1628+    if (p >= result.length) {
1629+        var str = "";
1630+        for (var i = 0; i < p - result.length - 1; i++) {
1631+            str += "0";
1632+        }
1633+        return str + result;
1634+    }
1635+};
1636+exports.BIN2OCT = BIN2OCT;
1637+/**
1638+ * Converts a decimal number to signed octal format.
1639+ * @param decimalDumber - The decimal value to be converted to signed octal,provided as a string. For this
1640+ * function, this value has a maximum of 536870911 if positive, and a minimum of -53687092 if negative.
1641+ * @param significantDigits - [ OPTIONAL ] The number of significant digits to ensure in the result. If this
1642+ * is greater than the number of significant digits in the result, the result is left-padded with zeros until the total
1643+ * number of digits reaches significant_digits.
1644+ * @returns {string} octal string representation of the decimal number
1645+ * @constructor
1646+ */
1647+var DEC2OCT = function (decimalDumber, significantDigits) {
1648+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "DEC2OCT");
1649+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(decimalDumber);
1650+    if (n < 0) {
1651+        n = Math.ceil(n);
1652+    }
1653+    if (n > 0) {
1654+        n = Math.floor(n);
1655+    }
1656+    var p = 10;
1657+    var placesPresent = false;
1658+    if (significantDigits !== undefined) {
1659+        p = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(significantDigits));
1660+        placesPresent = true;
1661+    }
1662+    if (n < -53687092 || n > 536870911) {
1663+        throw new Errors_1.NumError("Function DEC2OCT parameter 1 value is " + n + ". Valid values are between -53687092 and 536870911 inclusive.");
1664+    }
1665+    if (p < 1 || p > 10) {
1666+        throw new Errors_1.NumError("Function DEC2OCT parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
1667+    }
1668+    if (n < 0) {
1669+        return (1073741824 + n).toString(8).toUpperCase();
1670+    }
1671+    // Convert decimal number to hexadecimal
1672+    var result = parseInt(n.toString(), 10).toString(8).toUpperCase();
1673+    if (!placesPresent) {
1674+        return result;
1675+    }
1676+    var str = "";
1677+    for (var i = 0; i < p - result.length; i++) {
1678+        str += "0";
1679+    }
1680+    return str + result.toUpperCase();
1681+};
1682+exports.DEC2OCT = DEC2OCT;
1683+/**
1684+ * Converts a decimal number to signed hexadecimal format.
1685+ * @param decimalDumber - The decimal value to be converted to signed hexadecimal, provided as a string. This
1686+ * value has a maximum of 549755813887 if positive, and a minimum of -549755814888 if negative.
1687+ * @param significantDigits - [ OPTIONAL ] - The number of significant digits to ensure in the result. If
1688+ * this is greater than the number of significant digits in the result, the result is left-padded with zeros until the
1689+ * total number of digits reaches significant_digits. This value is ignored if decimal_number is negative.
1690+ * @returns {string} hexadecimal string representation of the decimal number
1691+ * @constructor
1692+ */
1693+var DEC2HEX = function (decimalDumber, significantDigits) {
1694+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "DEC2HEX");
1695+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(decimalDumber);
1696+    if (n < 0) {
1697+        n = Math.ceil(n);
1698+    }
1699+    if (n > 0) {
1700+        n = Math.floor(n);
1701+    }
1702+    var p = 10;
1703+    var placesPresent = false;
1704+    if (significantDigits !== undefined) {
1705+        p = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(significantDigits));
1706+        placesPresent = true;
1707+    }
1708+    if (n < -549755813888 || n > 549755813887) {
1709+        throw new Errors_1.NumError("Function DEC2HEX parameter 1 value is " + n + ". Valid values are between -549755813888 and 549755813887 inclusive.");
1710+    }
1711+    if (p < 1 || p > 10) {
1712+        throw new Errors_1.NumError("Function DEC2HEX parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
1713+    }
1714+    // Ignore places and return a 10-character hexadecimal number if number is negative
1715+    if (n < 0) {
1716+        return (1099511627776 + n).toString(16).toUpperCase();
1717+    }
1718+    // Convert decimal number to hexadecimal
1719+    var result = parseInt(n.toString(), 10).toString(16).toUpperCase();
1720+    if (!placesPresent) {
1721+        return result;
1722+    }
1723+    var str = "";
1724+    for (var i = 0; i < p - result.length; i++) {
1725+        str += "0";
1726+    }
1727+    return str + result;
1728+};
1729+exports.DEC2HEX = DEC2HEX;
1730+/**
1731+ * Converts a decimal number to signed binary format.
1732+ * @param decimalDumber - The decimal value to be converted to signed binary, provided as a string. For this
1733+ * function, this value has a maximum of 511 if positive, and a minimum of -512 if negative.
1734+ * @param significantDigits - [ OPTIONAL ] The number of significant digits to ensure in the result. If this
1735+ * is greater than the number of significant digits in the result, the result is left-padded with zeros until the total
1736+ * number of digits reaches significant_digits.
1737+ * @returns {string} signed binary string representation of the input decimal number.
1738+ * @constructor
1739+ */
1740+var DEC2BIN = function (decimalDumber, significantDigits) {
1741+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "DEC2BIN");
1742+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(decimalDumber);
1743+    if (n < 0) {
1744+        n = Math.ceil(n);
1745+    }
1746+    if (n > 0) {
1747+        n = Math.floor(n);
1748+    }
1749+    if (n === 0 || n === 1) {
1750+        return n.toString();
1751+    }
1752+    var p = 10;
1753+    var placesPresent = false;
1754+    if (significantDigits !== undefined) {
1755+        p = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(significantDigits));
1756+        placesPresent = true;
1757+    }
1758+    if (n < -512 || n > 511) {
1759+        throw new Errors_1.NumError("Function DEC2BIN parameter 1 value is " + n + ". Valid values are between -512 and 511 inclusive.");
1760+    }
1761+    if (p < 1 || p > 10) {
1762+        throw new Errors_1.NumError("Function DEC2BIN parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
1763+    }
1764+    // Ignore places and return a 10-character binary number if number is negative
1765+    if (n < 0) {
1766+        var count = (9 - (512 + n).toString(2).length);
1767+        var st = "";
1768+        for (var i = 0; i < count; i++) {
1769+            st += "0";
1770+        }
1771+        return "1" + st + (512 + n).toString(2);
1772+    }
1773+    // Convert decimal number to binary
1774+    var result = parseInt(n.toString(), 10).toString(2);
1775+    // Pad return value with leading 0s (zeros) if necessary
1776+    if (p >= result.length) {
1777+        var str = "";
1778+        for (var i = 0; i < (p - result.length); i++) {
1779+            str += "0";
1780+        }
1781+        var workingString = str + result;
1782+        if (!placesPresent) {
1783+            var returnString = "";
1784+            for (var i = 0; i < workingString.length; i++) {
1785+                var char = workingString[i];
1786+                if (char === "1") {
1787+                    break;
1788+                }
1789+                returnString = workingString.slice(i + 1);
1790+            }
1791+            return returnString;
1792+        }
1793+        return workingString;
1794+    }
1795+};
1796+exports.DEC2BIN = DEC2BIN;
1797+/**
1798+ * Compare two numeric values, returning 1 if they're equal.
1799+ * @param one - The first number to compare.
1800+ * @param two - The second number to compare.
1801+ * @returns {number} 1 if they're equal, 0 if they're not equal.
1802+ * @constructor
1803+ */
1804+var DELTA = function (one, two) {
1805+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "DELTA");
1806+    if (two === undefined) {
1807+        return TypeConverter_1.TypeConverter.valueToNumber(one) === 0 ? 1 : 0;
1808+    }
1809+    return TypeConverter_1.TypeConverter.valueToNumber(one) === TypeConverter_1.TypeConverter.valueToNumber(two) ? 1 : 0;
1810+};
1811+exports.DELTA = DELTA;
1812diff --git a/dist/Formulas/Financial.js b/dist/Formulas/Financial.js
1813new file mode 100644
1814index 0000000..c633f5c
1815--- /dev/null
1816+++ b/dist/Formulas/Financial.js
1817@@ -0,0 +1,416 @@
1818+"use strict";
1819+exports.__esModule = true;
1820+var ArgsChecker_1 = require("../Utilities/ArgsChecker");
1821+var TypeConverter_1 = require("../Utilities/TypeConverter");
1822+var Errors_1 = require("../Errors");
1823+var Date_1 = require("./Date");
1824+/**
1825+ * Calculates the depreciation of an asset for a specified period using the double-declining balance method.
1826+ * @param cost - The initial cost of the asset.
1827+ * @param salvage - The value of the asset at the end of depreciation.
1828+ * @param life - The number of periods over which the asset is depreciated.
1829+ * @param period - The single period within life for which to calculate depreciation.
1830+ * @param factor - [ OPTIONAL - 2 by default ] - The factor by which depreciation decreases.
1831+ * @returns {number} depreciation of an asset for a specified period
1832+ * @constructor
1833+ */
1834+var DDB = function (cost, salvage, life, period, factor) {
1835+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 4, 5, "DDB");
1836+    cost = TypeConverter_1.TypeConverter.firstValueAsNumber(cost);
1837+    salvage = TypeConverter_1.TypeConverter.firstValueAsNumber(salvage);
1838+    life = TypeConverter_1.TypeConverter.firstValueAsNumber(life);
1839+    period = TypeConverter_1.TypeConverter.firstValueAsNumber(period);
1840+    factor = factor === undefined ? 2 : TypeConverter_1.TypeConverter.firstValueAsNumber(factor);
1841+    if (cost < 0) {
1842+        throw new Errors_1.NumError("Function DDB parameter 1 value is "
1843+            + cost + ". It should be greater than or equal to 0.");
1844+    }
1845+    if (salvage < 0) {
1846+        throw new Errors_1.NumError("Function DDB parameter 2 value is "
1847+            + salvage + ". It should be greater than or equal to 0.");
1848+    }
1849+    if (life < 0) {
1850+        throw new Errors_1.NumError("Function DDB parameter 3 value is "
1851+            + life + ". It should be greater than or equal to 0.");
1852+    }
1853+    if (period < 0) {
1854+        throw new Errors_1.NumError("Function DDB parameter 4 value is "
1855+            + period + ". It should be greater than or equal to 0.");
1856+    }
1857+    if (period > life) {
1858+        throw new Errors_1.NumError("Function DDB parameter 4 value is "
1859+            + life + ". It should be less than or equal to value of Function DB parameter 3 with " + period + ".");
1860+    }
1861+    if (salvage >= cost) {
1862+        return 0;
1863+    }
1864+    var total = 0;
1865+    var current = 0;
1866+    for (var i = 1; i <= period; i++) {
1867+        current = Math.min((cost - total) * (factor / TypeConverter_1.checkForDevideByZero(life)), (cost - salvage - total));
1868+        total += current;
1869+    }
1870+    return current;
1871+};
1872+exports.DDB = DDB;
1873+/**
1874+ * Calculates the depreciation of an asset for a specified period using the arithmetic declining balance method.
1875+ * @param cost - The initial cost of the asset.
1876+ * @param salvage - The value of the asset at the end of depreciation.
1877+ * @param life - The number of periods over which the asset is depreciated.
1878+ * @param period - The single period within life for which to calculate depreciation.
1879+ * @param month - [ OPTIONAL - 12 by default ] - The number of months in the first year of depreciation.
1880+ * @returns {number} depreciated value
1881+ * @constructor
1882+ */
1883+var DB = function (cost, salvage, life, period, month) {
1884+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 4, 5, "DB");
1885+    cost = TypeConverter_1.TypeConverter.firstValueAsNumber(cost);
1886+    salvage = TypeConverter_1.TypeConverter.firstValueAsNumber(salvage);
1887+    life = TypeConverter_1.TypeConverter.firstValueAsNumber(life);
1888+    period = TypeConverter_1.TypeConverter.firstValueAsNumber(period);
1889+    month = month !== undefined ? Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(month)) : 12;
1890+    if (cost < 0) {
1891+        throw new Errors_1.NumError("Function DB parameter 1 value is "
1892+            + cost + ". It should be greater than or equal to 0.");
1893+    }
1894+    if (salvage < 0) {
1895+        throw new Errors_1.NumError("Function DB parameter 2 value is "
1896+            + salvage + ". It should be greater than or equal to 0.");
1897+    }
1898+    if (life < 0) {
1899+        throw new Errors_1.NumError("Function DB parameter 3 value is "
1900+            + life + ". It should be greater than or equal to 0.");
1901+    }
1902+    if (period < 0) {
1903+        throw new Errors_1.NumError("Function DB parameter 4 value is "
1904+            + period + ". It should be greater than or equal to 0.");
1905+    }
1906+    if (month > 12 || month < 1) {
1907+        throw new Errors_1.NumError("Function DB parameter 5 value is "
1908+            + month + ". Valid values are between 1 and 12 inclusive.");
1909+    }
1910+    if (period > life) {
1911+        throw new Errors_1.NumError("Function DB parameter 4 value is "
1912+            + life + ". It should be less than or equal to value of Function DB parameter 3 with " + period + ".");
1913+    }
1914+    if (salvage >= cost) {
1915+        return 0;
1916+    }
1917+    if (cost === 0 && salvage !== 0) {
1918+        throw new Errors_1.DivZeroError("Evaluation of function DB cause a divide by zero error.");
1919+    }
1920+    var rate = (1 - Math.pow(salvage / cost, 1 / life));
1921+    var initial = cost * rate * month / 12;
1922+    var total = initial;
1923+    var current = 0;
1924+    var ceiling = (period === life) ? life - 1 : period;
1925+    for (var i = 2; i <= ceiling; i++) {
1926+        current = (cost - total) * rate;
1927+        total += current;
1928+    }
1929+    if (period === 1) {
1930+        return initial;
1931+    }
1932+    else if (period === life) {
1933+        return (cost - total) * rate;
1934+    }
1935+    else {
1936+        return current;
1937+    }
1938+};
1939+exports.DB = DB;
1940+/**
1941+ * Formats a number into the locale-specific currency format. WARNING: Currently the equivalent of TRUNC, since this
1942+ * returns numbers
1943+ * @param number - The value to be formatted.
1944+ * @param places - [ OPTIONAL - 2 by default ] - The number of decimal places to display.
1945+ * @returns {number} dollars
1946+ * @constructor
1947+ */
1948+var DOLLAR = function (number, places) {
1949+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "DOLLAR");
1950+    var v = TypeConverter_1.TypeConverter.firstValueAsNumber(number);
1951+    places = places !== undefined ? TypeConverter_1.TypeConverter.firstValueAsNumber(places) : 2;
1952+    var sign = (v > 0) ? 1 : -1;
1953+    var divisor = sign * (Math.floor(Math.abs(v) * Math.pow(10, places)));
1954+    var pow = Math.pow(10, places);
1955+    if (pow === 0 && divisor !== 0) {
1956+        throw new Errors_1.DivZeroError("Evaluation of function DOLLAR cause a divide by zero error.");
1957+    }
1958+    return divisor / pow;
1959+};
1960+exports.DOLLAR = DOLLAR;
1961+/**
1962+ * Converts a price quotation given as a decimal fraction into a decimal value.
1963+ * @param fractionalPrice - The price quotation given using fractional decimal conventions.
1964+ * @param unit - The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.
1965+ * @returns {number} decimal value.
1966+ * @constructor
1967+ */
1968+var DOLLARDE = function (fractionalPrice, unit) {
1969+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "DOLLARDE");
1970+    var dollar = TypeConverter_1.TypeConverter.firstValueAsNumber(fractionalPrice);
1971+    var fraction = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(unit));
1972+    if (fraction === 0) {
1973+        throw new Errors_1.DivZeroError("Function DOLLARDE parameter 2 cannot be zero.");
1974+    }
1975+    var result = parseInt(dollar.toString(), 10);
1976+    result += (dollar % 1) * Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN10)) / fraction;
1977+    var power = Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN2) + 1);
1978+    if (power === 0) {
1979+        throw new Errors_1.DivZeroError("Evaluation of function DOLLARDE cause a divide by zero error.");
1980+    }
1981+    result = Math.round(result * power) / power;
1982+    return result;
1983+};
1984+exports.DOLLARDE = DOLLARDE;
1985+/**
1986+ * Converts a price quotation given as a decimal value into a decimal fraction.
1987+ * @param decimalPrice - The price quotation given as a decimal value.
1988+ * @param unit - The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds
1989+ * @returns {number} price quotation as decimal fraction.
1990+ * @constructor
1991+ */
1992+var DOLLARFR = function (decimalPrice, unit) {
1993+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "DOLLARFR");
1994+    decimalPrice = TypeConverter_1.TypeConverter.firstValueAsNumber(decimalPrice);
1995+    unit = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(unit));
1996+    if (unit === 0) {
1997+        throw new Errors_1.DivZeroError("Function DOLLARFR parameter 2 cannot be zero.");
1998+    }
1999+    var result = parseInt(decimalPrice.toString(), 10);
2000+    result += (decimalPrice % 1) * Math.pow(10, -Math.ceil(Math.log(unit) / Math.LN10)) * unit;
2001+    return result;
2002+};
2003+exports.DOLLARFR = DOLLARFR;
2004+/**
2005+ * Calculates the annual effective interest rate given the nominal rate and number of compounding periods per year.
2006+ * @param nominalRate - The nominal interest rate per year.
2007+ * @param periodsPerYear - The number of compounding periods per year.
2008+ * @returns {number} annual effective interest rate
2009+ * @constructor
2010+ */
2011+var EFFECT = function (nominalRate, periodsPerYear) {
2012+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "EFFECT");
2013+    var rate = TypeConverter_1.TypeConverter.firstValueAsNumber(nominalRate);
2014+    var periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periodsPerYear);
2015+    if (rate <= 0) {
2016+        throw new Errors_1.NumError("Function EFFECT parameter 1 value is " + rate + ". It should be greater than to 0");
2017+    }
2018+    if (periods < 1) {
2019+        throw new Errors_1.NumError("Function EFFECT parameter 2 value is " + periods + ". It should be greater than or equal to 1");
2020+    }
2021+    periods = Math.floor(periods);
2022+    return Math.pow(1 + rate / periods, periods) - 1;
2023+};
2024+exports.EFFECT = EFFECT;
2025+/**
2026+ * Calculates the periodic payment for an annuity investment based on constant-amount periodic payments and a constant
2027+ * interest rate.
2028+ * @param rate - The interest rate.
2029+ * @param periods - The number of payments to be made.
2030+ * @param presentValue - The current value of the annuity.
2031+ * @param futureValue [ OPTIONAL ] - The future value remaining after the final payment has been made.
2032+ * @param endOrBeginning [ OPTIONAL - 0 by default ] - Whether payments are due at the end (0) or beginning (1) of each
2033+ * period.
2034+ * @returns {number}
2035+ * @constructor
2036+ */
2037+var PMT = function (rate, periods, presentValue, futureValue, endOrBeginning) {
2038+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 5, "PMT");
2039+    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
2040+    periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
2041+    presentValue = TypeConverter_1.TypeConverter.firstValueAsNumber(presentValue);
2042+    futureValue = futureValue ? TypeConverter_1.TypeConverter.firstValueAsNumber(futureValue) : 0;
2043+    endOrBeginning = endOrBeginning ? TypeConverter_1.TypeConverter.firstValueAsNumber(endOrBeginning) : 0;
2044+    var result;
2045+    if (rate === 0) {
2046+        result = (presentValue + futureValue) / periods;
2047+    }
2048+    else {
2049+        var term = Math.pow(1 + rate, periods);
2050+        if (endOrBeginning) {
2051+            result = (futureValue * rate / (term - 1) + presentValue * rate / (1 - 1 / term)) / (1 + rate);
2052+        }
2053+        else {
2054+            result = futureValue * rate / (term - 1) + presentValue * rate / (1 - 1 / term);
2055+        }
2056+    }
2057+    return -result;
2058+};
2059+exports.PMT = PMT;
2060+// TODO: Convert to real formula FV
2061+function fv(rate, periods, payment, value, type) {
2062+    var result;
2063+    if (rate === 0) {
2064+        result = value + payment * periods;
2065+    }
2066+    else {
2067+        var term = Math.pow(1 + rate, periods);
2068+        if (type) {
2069+            result = value * term + payment * (1 + rate) * (term - 1.0) / rate;
2070+        }
2071+        else {
2072+            result = value * term + payment * (term - 1) / rate;
2073+        }
2074+    }
2075+    return -result;
2076+}
2077+/**
2078+ * Calculates the cumulative principal paid over a range of payment periods for an investment based on constant-amount
2079+ * periodic payments and a constant interest rate.
2080+ * @param rate - The interest rate.
2081+ * @param numberOfPeriods - The number of payments to be made.
2082+ * @param presentValue - The current value of the annuity.
2083+ * @param firstPeriod - The number of the payment period to begin the cumulative calculation. must be greater
2084+ * than or equal to 1.
2085+ * @param lastPeriod - The number of the payment period to end the cumulative calculation, must be greater
2086+ * than first_period.
2087+ * @param endOrBeginning - Whether payments are due at the end (0) or beginning (1) of each period
2088+ * @returns {number} cumulative principal
2089+ * @constructor
2090+ */
2091+var CUMPRINC = function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning) {
2092+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 6, "CUMPRINC");
2093+    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
2094+    var periods = TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfPeriods);
2095+    var value = TypeConverter_1.TypeConverter.firstValueAsNumber(presentValue);
2096+    var start = TypeConverter_1.TypeConverter.firstValueAsNumber(firstPeriod);
2097+    if (start < 1) {
2098+        throw new Errors_1.NumError("Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
2099+    }
2100+    var end = TypeConverter_1.TypeConverter.firstValueAsNumber(lastPeriod);
2101+    if (end < 1) {
2102+        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
2103+    }
2104+    if (end < start) {
2105+        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
2106+    }
2107+    var type = TypeConverter_1.TypeConverter.firstValueAsBoolean(endOrBeginning);
2108+    var payment = PMT(rate, periods, value, 0, type);
2109+    var principal = 0;
2110+    if (start === 1) {
2111+        if (type) {
2112+            principal = payment;
2113+        }
2114+        else {
2115+            principal = payment + value * rate;
2116+        }
2117+        start++;
2118+    }
2119+    for (var i = start; i <= end; i++) {
2120+        if (type) {
2121+            principal += payment - (fv(rate, i - 2, payment, value, 1) - payment) * rate;
2122+        }
2123+        else {
2124+            principal += payment - fv(rate, i - 1, payment, value, 0) * rate;
2125+        }
2126+    }
2127+    return principal;
2128+};
2129+exports.CUMPRINC = CUMPRINC;
2130+/**
2131+ * Calculates the cumulative interest over a range of payment periods for an investment based on constant-amount
2132+ * periodic payments and a constant interest rate.
2133+ * @param rate - The interest rate.
2134+ * @param numberOfPeriods - The number of payments to be made.
2135+ * @param presentValue - The current value of the annuity.
2136+ * @param firstPeriod - The number of the payment period to begin the cumulative calculation, must be greater
2137+ * than or equal to 1.
2138+ * @param lastPeriod - The number of the payment period to end the cumulative calculation, must be greater
2139+ * than first_period.
2140+ * @param endOrBeginning - Whether payments are due at the end (0) or beginning (1) of each period.
2141+ * @returns {number} cumulative interest
2142+ * @constructor
2143+ */
2144+var CUMIPMT = function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning) {
2145+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 6, "CUMIPMT");
2146+    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
2147+    var periods = TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfPeriods);
2148+    var value = TypeConverter_1.TypeConverter.firstValueAsNumber(presentValue);
2149+    var start = TypeConverter_1.TypeConverter.firstValueAsNumber(firstPeriod);
2150+    if (start < 1) {
2151+        throw new Errors_1.NumError("Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
2152+    }
2153+    var end = TypeConverter_1.TypeConverter.firstValueAsNumber(lastPeriod);
2154+    if (end < 1) {
2155+        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
2156+    }
2157+    if (end < start) {
2158+        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
2159+    }
2160+    var type = TypeConverter_1.TypeConverter.firstValueAsBoolean(endOrBeginning);
2161+    var payment = PMT(rate, periods, value, 0, type);
2162+    var interest = 0;
2163+    if (start === 1) {
2164+        if (!type) {
2165+            interest = -value;
2166+            start++;
2167+        }
2168+        else {
2169+            start++;
2170+        }
2171+    }
2172+    for (var i = start; i <= end; i++) {
2173+        if (type) {
2174+            interest += fv(rate, i - 2, payment, value, 1) - payment;
2175+        }
2176+        else {
2177+            interest += fv(rate, i - 1, payment, value, 0);
2178+        }
2179+    }
2180+    interest *= rate;
2181+    return interest;
2182+};
2183+exports.CUMIPMT = CUMIPMT;
2184+/**
2185+ * Calculates the accrued interest of a security that has periodic payments.
2186+ * WARNING: This function has been implemented to specifications as outlined in Google Spreadsheets, LibreOffice, and
2187+ * OpenOffice. It functions much the same as MSExcel's ACCRINT, but there are several key differences. Below are links
2188+ * to illustrate the differences. Please see the source code for more information on differences. Links: https://quant.stackexchange.com/questions/7040/whats-the-algorithm-behind-excels-accrint, https://support.office.com/en-us/article/ACCRINT-function-fe45d089-6722-4fb3-9379-e1f911d8dc74, https://quant.stackexchange.com/questions/7040/whats-the-algorithm-behind-excels-accrint, https://support.google.com/docs/answer/3093200 .
2189+ * @param issue - The date the security was initially issued.
2190+ * @param firstPayment - The first date interest will be paid.
2191+ * @param settlement - The settlement date of the security, the date after issuance when the security is
2192+ * delivered to the buyer. Is the maturity date of the security if it is held until maturity rather than sold.
2193+ * @param rate - The annualized rate of interest.
2194+ * @param redemption - The redemption amount per 100 face value, or par.
2195+ * @param frequency - The number of coupon payments per year. For annual payments, frequency = 1; for
2196+ * semiannual, frequency = 2; for quarterly, frequency = 4.
2197+ * @param dayCountConvention - [ OPTIONAL - 0 by default ] - An indicator of what day count method to use.
2198+ * 0 or omitted = US (NASD) 30/360, 1 = Actual/actual, 2 = Actual/360, 3 = Actual/365, 4 = European 30/360.
2199+ * @returns {number}
2200+ * @constructor
2201+ * TODO: This function is based off of the open-source versions I was able to dig up online. We should implement a
2202+ * TODO:     second version that is closer to what MSExcel does and is named something like `ACCRINT.MS`.
2203+ */
2204+var ACCRINT = function (issue, firstPayment, settlement, rate, redemption, frequency, dayCountConvention) {
2205+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 6, 7, "ACCRINT");
2206+    issue = TypeConverter_1.TypeConverter.firstValueAsDateNumber(issue);
2207+    // "firstPayment" param is only here to check for errors for GS implementation.
2208+    // In MSE, there is a 7th (zero-indexed-6th) param that indicates the calculation-method to use, which indicates
2209+    // weather the total accrued interest starting at the first_intrest date, instead of the issue date.
2210+    firstPayment = TypeConverter_1.TypeConverter.firstValueAsDateNumber(firstPayment);
2211+    if (firstPayment < 0) {
2212+        throw new Errors_1.NumError("Function ACCRINT parameter 2 value is " + firstPayment
2213+            + ". It should be greater than 0.");
2214+    }
2215+    settlement = TypeConverter_1.TypeConverter.firstValueAsDateNumber(settlement);
2216+    if (issue > settlement) {
2217+        throw new Errors_1.NumError("Function ACCRINT parameter 1 (" + issue.toString()
2218+            + ") should be on or before Function ACCRINT parameter 3 (" + settlement.toString() + ").");
2219+    }
2220+    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
2221+    // redemption, aka "par"
2222+    redemption = TypeConverter_1.TypeConverter.firstValueAsNumber(redemption);
2223+    // The frequency parameter also does not affect the resulting value of the formula in the GS implementation.
2224+    // In MSE, frequency is used to calculate a more accurate value, by breaking apart the year, and computing interest
2225+    // on an on-going basis. In this implementation, we use YEARFRAC to get a numerical value that encompasses the
2226+    // functionality of "frequency".
2227+    frequency = TypeConverter_1.TypeConverter.firstValueAsNumber(frequency);
2228+    // dayCountConvention, aka "basis"
2229+    dayCountConvention = dayCountConvention !== undefined ? TypeConverter_1.TypeConverter.firstValueAsNumber(dayCountConvention) : 1;
2230+    var factor = Date_1.YEARFRAC(issue, settlement, dayCountConvention);
2231+    return redemption * rate * factor;
2232+};
2233+exports.ACCRINT = ACCRINT;
2234diff --git a/dist/Formulas/Logical.js b/dist/Formulas/Logical.js
2235new file mode 100644
2236index 0000000..e09f10a
2237--- /dev/null
2238+++ b/dist/Formulas/Logical.js
2239@@ -0,0 +1,167 @@
2240+"use strict";
2241+exports.__esModule = true;
2242+var ArgsChecker_1 = require("../Utilities/ArgsChecker");
2243+var TypeConverter_1 = require("../Utilities/TypeConverter");
2244+var Errors_1 = require("../Errors");
2245+/**
2246+ * Returns true if all of the provided arguments are logically true, and false if any of the provided arguments are
2247+ * logically false.
2248+ * @param values At least one expression or reference to a cell containing an expression that represents some logical
2249+ * value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.
2250+ * @returns {boolean} if all values are logically true.
2251+ * @constructor
2252+ */
2253+var AND = function () {
2254+    var values = [];
2255+    for (var _i = 0; _i < arguments.length; _i++) {
2256+        values[_i] = arguments[_i];
2257+    }
2258+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "AND");
2259+    var result = true;
2260+    for (var i = 0; i < values.length; i++) {
2261+        if (typeof values[i] === "string") {
2262+            throw new Errors_1.ValueError("AND expects boolean values. But '" + values[i]
2263+                + "' is a text and cannot be coerced to a boolean.");
2264+        }
2265+        else if (values[i] instanceof Array) {
2266+            if (!AND.apply(this, values[i])) {
2267+                result = false;
2268+                break;
2269+            }
2270+        }
2271+        else if (!values[i]) {
2272+            result = false;
2273+            break;
2274+        }
2275+    }
2276+    return result;
2277+};
2278+exports.AND = AND;
2279+/**
2280+ * Tests whether two strings are identical, returning true if they are.
2281+ * @param one - The first string to compare
2282+ * @param two - The second string to compare
2283+ * @returns {boolean}
2284+ * @constructor
2285+ */
2286+var EXACT = function (one, two) {
2287+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "EXACT");
2288+    one = TypeConverter_1.TypeConverter.firstValue(one);
2289+    two = TypeConverter_1.TypeConverter.firstValue(two);
2290+    return one.toString() === two.toString();
2291+};
2292+exports.EXACT = EXACT;
2293+/**
2294+ * Returns true.
2295+ * @returns {boolean} true boolean
2296+ * @constructor
2297+ */
2298+var TRUE = function () {
2299+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 0, "TRUE");
2300+    return true;
2301+};
2302+exports.TRUE = TRUE;
2303+/**
2304+ * Returns false.
2305+ * @returns {boolean} false boolean
2306+ * @constructor
2307+ */
2308+var FALSE = function () {
2309+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 0, "FALSE");
2310+    return false;
2311+};
2312+exports.FALSE = FALSE;
2313+/**
2314+ * Returns the opposite of a logical value - NOT(TRUE) returns FALSE; NOT(FALSE) returns TRUE.
2315+ * @param value - An expression or reference to a cell holding an expression that represents some logical value.
2316+ * @returns {boolean} opposite of a logical value input
2317+ * @constructor
2318+ */
2319+var NOT = function (value) {
2320+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "NOT");
2321+    if (typeof (value) === "boolean") {
2322+        return !value;
2323+    }
2324+    if (typeof (value) === "string") {
2325+        if (value === "") {
2326+            return true;
2327+        }
2328+        throw new Errors_1.ValueError("Function NOT parameter 1 expects boolean values. But '" + value
2329+            + "' is a text and cannot be coerced to a boolean.");
2330+    }
2331+    if (typeof (value) === "number") {
2332+        return value === 0;
2333+    }
2334+    if (value instanceof Array) {
2335+        if (value.length === 0) {
2336+            throw new Errors_1.RefError("Reference does not exist.");
2337+        }
2338+        return NOT(value[0]);
2339+    }
2340+};
2341+exports.NOT = NOT;
2342+/**
2343+ * Returns true if any of the provided arguments are logically true, and false if all of the provided arguments are
2344+ * logically false.
2345+ * @param values An expression or reference to a cell containing an expression that represents some logical value, i.e.
2346+ * TRUE or FALSE, or an expression that can be coerced to a logical value.
2347+ * @returns {boolean}
2348+ * @constructor
2349+ */
2350+var OR = function () {
2351+    var values = [];
2352+    for (var _i = 0; _i < arguments.length; _i++) {
2353+        values[_i] = arguments[_i];
2354+    }
2355+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "OR");
2356+    for (var i = 0; i < values.length; i++) {
2357+        if (values[i] instanceof Array) {
2358+            if (values[i].length === 0) {
2359+                throw new Errors_1.RefError("Reference does not exist.");
2360+            }
2361+            if (OR.apply(this, values[i])) {
2362+                return true;
2363+            }
2364+        }
2365+        else if (TypeConverter_1.TypeConverter.valueToBoolean(values[i])) {
2366+            return true;
2367+        }
2368+    }
2369+    return false;
2370+};
2371+exports.OR = OR;
2372+/**
2373+ * Exclusive or or exclusive disjunction is a logical operation that outputs true only when inputs differ.
2374+ * @param values to check for exclusivity.
2375+ * @returns {boolean} returns true if only one input is considered logically true.
2376+ * @constructor
2377+ */
2378+var XOR = function () {
2379+    var values = [];
2380+    for (var _i = 0; _i < arguments.length; _i++) {
2381+        values[_i] = arguments[_i];
2382+    }
2383+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "XOR");
2384+    var alreadyTruthy = false;
2385+    for (var i = 0; i < values.length; i++) {
2386+        if (values[i] instanceof Array) {
2387+            if (values[i].length === 0) {
2388+                throw new Errors_1.RefError("Reference does not exist.");
2389+            }
2390+            if (XOR.apply(this, values[i])) {
2391+                if (alreadyTruthy) {
2392+                    return false;
2393+                }
2394+                alreadyTruthy = true;
2395+            }
2396+        }
2397+        else if (TypeConverter_1.TypeConverter.valueToBoolean(values[i])) {
2398+            if (alreadyTruthy) {
2399+                return false;
2400+            }
2401+            alreadyTruthy = true;
2402+        }
2403+    }
2404+    return alreadyTruthy;
2405+};
2406+exports.XOR = XOR;
2407diff --git a/dist/Formulas/Math.js b/dist/Formulas/Math.js
2408new file mode 100644
2409index 0000000..0603a00
2410--- /dev/null
2411+++ b/dist/Formulas/Math.js
2412@@ -0,0 +1,983 @@
2413+"use strict";
2414+exports.__esModule = true;
2415+var ArgsChecker_1 = require("../Utilities/ArgsChecker");
2416+var TypeConverter_1 = require("../Utilities/TypeConverter");
2417+var Filter_1 = require("../Utilities/Filter");
2418+var Serializer_1 = require("../Utilities/Serializer");
2419+var CriteriaFunctionFactory_1 = require("../Utilities/CriteriaFunctionFactory");
2420+var Errors_1 = require("../Errors");
2421+var MathHelpers_1 = require("../Utilities/MathHelpers");
2422+/**
2423+ * Returns the absolute value of a number.
2424+ * @param value to get the absolute value of.
2425+ * @returns {number} absolute value
2426+ * @constructor
2427+ */
2428+var ABS = function (value) {
2429+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ABS");
2430+    var v = TypeConverter_1.TypeConverter.valueToNumber(value);
2431+    return Math.abs(v);
2432+};
2433+exports.ABS = ABS;
2434+/**
2435+ * Returns the inverse cosine of a value, in radians.
2436+ * @param value The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive.
2437+ * @returns {number} inverse cosine of value
2438+ * @constructor
2439+ */
2440+var ACOS = function (value) {
2441+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ACOS");
2442+    value = TypeConverter_1.TypeConverter.valueToNumber(value);
2443+    if (value === -1) {
2444+        return Math.PI;
2445+    }
2446+    else if (value > 1 || value < -1) {
2447+        throw new Errors_1.NumError("Function ACOS parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
2448+    }
2449+    return Math.acos(value);
2450+};
2451+exports.ACOS = ACOS;
2452+/**
2453+ * Returns the inverse hyperbolic cosine of a number.
2454+ * @param value The value for which to calculate the inverse hyperbolic cosine. Must be greater than or equal to 1.
2455+ * @returns {number} to find the inverse hyperbolic cosine for.
2456+ * @constructor
2457+ */
2458+var ACOSH = function (value) {
2459+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ACOSH");
2460+    value = TypeConverter_1.TypeConverter.valueToNumber(value);
2461+    if (value < 1) {
2462+        throw new Errors_1.NumError("Function ACOSH parameter 1 value is " + value + ". It should be greater than or equal to 1.");
2463+    }
2464+    return Math.log(value + Math.sqrt(value * value - 1));
2465+};
2466+exports.ACOSH = ACOSH;
2467+/**
2468+ * Calculate the hyperbolic arc-cotangent of a value
2469+ * @param value number not between -1 and 1 inclusively.
2470+ * @returns {number} hyperbolic arc-cotangent
2471+ * @constructor
2472+ */
2473+var ACOTH = function (value) {
2474+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ACOTH");
2475+    value = TypeConverter_1.TypeConverter.valueToNumber(value);
2476+    if (value <= 1 && value >= -1) {
2477+        throw new Errors_1.NumError("Function ACOTH parameter 1 value is " + value + ". Valid values cannot be between -1 and 1 inclusive.");
2478+    }
2479+    return 0.5 * Math.log((value + 1) / (value - 1));
2480+};
2481+exports.ACOTH = ACOTH;
2482+/**
2483+ * Returns the inverse sine of a value, in radians.
2484+ * @param value The value for which to calculate the inverse sine. Must be between -1 and 1, inclusive.
2485+ * @returns {number} inverse sine of input value
2486+ * @constructor
2487+ */
2488+var ASIN = function (value) {
2489+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ASIN");
2490+    value = TypeConverter_1.TypeConverter.valueToNumber(value);
2491+    if (value === -1) {
2492+        return Math.PI;
2493+    }
2494+    else if (value > 1 || value < -1) {
2495+        throw new Errors_1.NumError("Function ASIN parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
2496+    }
2497+    return Math.asin(value);
2498+};
2499+exports.ASIN = ASIN;
2500+/**
2501+ * Returns the inverse hyperbolic sine of a number.
2502+ * @param value The value for which to calculate the inverse hyperbolic sine.
2503+ * @returns {number} inverse hyperbolic sine of input
2504+ * @constructor
2505+ */
2506+var ASINH = function (value) {
2507+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ASINH");
2508+    value = TypeConverter_1.TypeConverter.valueToNumber(value);
2509+    return Math.log(value + Math.sqrt(value * value + 1));
2510+};
2511+exports.ASINH = ASINH;
2512+/**
2513+ * Returns the inverse tangent of a value, in radians.
2514+ * @param value The value for which to calculate the inverse tangent.
2515+ * @returns {number} inverse tangent of input value
2516+ * @constructor
2517+ */
2518+var ATAN = function (value) {
2519+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ATAN");
2520+    value = TypeConverter_1.TypeConverter.valueToNumber(value);
2521+    if (value === -1) {
2522+        return Math.PI;
2523+    }
2524+    else if (value > 1 || value < -1) {
2525+        throw new Errors_1.NumError("Function ATAN parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
2526+    }
2527+    return Math.atan(value);
2528+};
2529+exports.ATAN = ATAN;
2530+/**
2531+ * Returns the angle between the x-axis and a line segment from the origin (0,0) to specified coordinate pair (x,y), in radians.
2532+ * @param x The x coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.
2533+ * @param y The y coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.
2534+ * @returns {number} angle in radians
2535+ * @constructor
2536+ */
2537+var ATAN2 = function (x, y) {
2538+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "ATAN2");
2539+    x = TypeConverter_1.TypeConverter.valueToNumber(x);
2540+    y = TypeConverter_1.TypeConverter.valueToNumber(y);
2541+    if (x === 0 && y === 0) {
2542+        throw new Errors_1.DivZeroError("Evaluation of function ATAN2 caused a divide by zero error.");
2543+    }
2544+    return Math.atan2(y, x);
2545+};
2546+exports.ATAN2 = ATAN2;
2547+/**
2548+ * Returns the inverse hyperbolic tangent of a number.
2549+ * @param value The value for which to calculate the inverse hyperbolic tangent. Must be between -1 and 1, exclusive.
2550+ * @returns {number} inverse hyperbolic tangent of input
2551+ * @constructor
2552+ */
2553+var ATANH = function (value) {
2554+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ATANH");
2555+    value = TypeConverter_1.TypeConverter.valueToNumber(value);
2556+    if (value >= 1 || value <= -1) {
2557+        throw new Errors_1.NumError("Function ATANH parameter 1 value is " + value + ". Valid values are between -1 and 1 exclusive.");
2558+    }
2559+    if (Math.abs(value) < 1) {
2560+    }
2561+    return Math["atanh"](value);
2562+};
2563+exports.ATANH = ATANH;
2564+/**
2565+ * Rounds a number up to the nearest even integer.
2566+ * @param value The value to round to the next greatest even number.
2567+ * @returns {number} next greatest even number
2568+ * @constructor
2569+ */
2570+var EVEN = function (value) {
2571+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "EVEN");
2572+    var X = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2573+    return X % 2 === 1 ? X + 1 : X;
2574+};
2575+exports.EVEN = EVEN;
2576+/**
2577+ * Returns the result of the modulo operator, the remainder after a division operation.
2578+ * @param dividend The number to be divided to find the remainder.
2579+ * @param divisor The number to divide by.
2580+ * @returns {number}
2581+ * @constructor
2582+ */
2583+var MOD = function (dividend, divisor) {
2584+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "MOD");
2585+    var oneN = TypeConverter_1.TypeConverter.valueToNumber(dividend);
2586+    var twoN = TypeConverter_1.TypeConverter.valueToNumber(divisor);
2587+    if (twoN === 0) {
2588+        throw new Errors_1.DivZeroError("Function MOD parameter 2 cannot be zero.");
2589+    }
2590+    return oneN % twoN;
2591+};
2592+exports.MOD = MOD;
2593+/**
2594+ * Rounds a number up to the nearest odd integer.
2595+ * @param value The value to round to the next greatest odd number.
2596+ * @returns {number} value to round up to next greatest odd number.
2597+ * @constructor
2598+ */
2599+var ODD = function (value) {
2600+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ODD");
2601+    var X = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2602+    return X % 2 === 1 ? X : X + 1;
2603+};
2604+exports.ODD = ODD;
2605+/**
2606+ * Returns a number raised to a power.
2607+ * @param base - The number to raise to the exponent power.
2608+ * @param exponent - The exponent to raise base to.
2609+ * @returns {number} resulting number
2610+ * @constructor
2611+ */
2612+var POWER = function (base, exponent) {
2613+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "POWER");
2614+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(base);
2615+    var p = TypeConverter_1.TypeConverter.firstValueAsNumber(exponent);
2616+    return Math.pow(n, p);
2617+};
2618+exports.POWER = POWER;
2619+/**
2620+ * Returns the sum of a series of numbers and/or cells.
2621+ * @param values The first number or range to add together.
2622+ * @returns {number} The sum of the series
2623+ * @constructor
2624+ */
2625+var SUM = function () {
2626+    var values = [];
2627+    for (var _i = 0; _i < arguments.length; _i++) {
2628+        values[_i] = arguments[_i];
2629+    }
2630+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "SUM");
2631+    var result = 0;
2632+    for (var i = 0; i < values.length; i++) {
2633+        if (values[i] instanceof Array) {
2634+            result = result + SUM.apply(this, values[i]);
2635+        }
2636+        else {
2637+            if (values[i] === "") {
2638+                throw new Errors_1.ValueError("Function SUM parameter " + i + " expects number values. But '" + values[i] + "' is a text and cannot be coerced to a number.");
2639+            }
2640+            result = result + TypeConverter_1.TypeConverter.valueToNumber(values[i]);
2641+        }
2642+    }
2643+    return result;
2644+};
2645+exports.SUM = SUM;
2646+/**
2647+ * Returns the positive square root of a positive number.
2648+ * @param value - The number for which to calculate the positive square root.
2649+ * @returns {number} square root
2650+ * @constructor
2651+ */
2652+var SQRT = function (value) {
2653+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "SQRT");
2654+    var x = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2655+    if (x < 0) {
2656+        throw new Errors_1.ValueError("Function SQRT parameter 1 value is " + x + ". It should be greater than or equal to 0.");
2657+    }
2658+    return Math.sqrt(x);
2659+};
2660+exports.SQRT = SQRT;
2661+/**
2662+ * Returns the positive square root of the product of Pi and the given positive number.
2663+ * @param value - The number which will be multiplied by Pi and have the product's square root returned
2664+ * @returns {number} the positive square root of the product of Pi and the given positive number.
2665+ * @constructor
2666+ */
2667+var SQRTPI = function (value) {
2668+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "SQRTPI");
2669+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2670+    if (n < 0) {
2671+        throw new Errors_1.NumError("Function SQRTPI parameter 1 value is " + n + ". It should be greater than or equal to 0.");
2672+    }
2673+    return Math.sqrt(n * Math.PI);
2674+};
2675+exports.SQRTPI = SQRTPI;
2676+/**
2677+ * Returns the cosine of an angle provided in radians.
2678+ * @param value - The angle to find the cosine of, in radians.
2679+ * @returns {number} cosine of angle
2680+ * @constructor
2681+ */
2682+var COS = function (value) {
2683+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "COS");
2684+    var r = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2685+    return Math.cos(r);
2686+};
2687+exports.COS = COS;
2688+/**
2689+ * Returns the hyperbolic cosine of any real number.
2690+ * @param value - Any real value to calculate the hyperbolic cosine of.
2691+ * @returns {number} the hyperbolic cosine of the input
2692+ * @constructor
2693+ */
2694+var COSH = function (value) {
2695+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "COSH");
2696+    var r = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2697+    return Math["cosh"](r);
2698+};
2699+exports.COSH = COSH;
2700+/**
2701+ * Returns the cotangent of any real number. Defined as cot(x) = 1 / tan(x).
2702+ * @param value - number to calculate the cotangent for
2703+ * @returns {number} cotangent
2704+ * @constructor
2705+ */
2706+var COT = function (value) {
2707+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "COT");
2708+    var x = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2709+    if (x === 0) {
2710+        throw new Errors_1.DivZeroError("Evaluation of function COT caused a divide by zero error.");
2711+    }
2712+    return 1 / Math.tan(x);
2713+};
2714+exports.COT = COT;
2715+/**
2716+ * Return the hyperbolic cotangent of a value, defined as coth(x) = 1 / tanh(x).
2717+ * @param value - value to calculate the hyperbolic cotangent value of
2718+ * @returns {number} hyperbolic cotangent
2719+ * @constructor
2720+ */
2721+var COTH = function (value) {
2722+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "COTH");
2723+    var x = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2724+    if (x === 0) {
2725+        throw new Errors_1.DivZeroError("Evaluation of function COTH caused a divide by zero error.");
2726+    }
2727+    return 1 / Math["tanh"](x);
2728+};
2729+exports.COTH = COTH;
2730+/**
2731+ * Rounds a number down to the nearest integer that is less than or equal to it.
2732+ * @param value -  The value to round down to the nearest integer.
2733+ * @returns {number} Rounded number
2734+ * @constructor
2735+ */
2736+var INT = function (value) {
2737+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "INT");
2738+    var x = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2739+    return Math.floor(x);
2740+};
2741+exports.INT = INT;
2742+/**
2743+ * Checks whether the provided value is even.
2744+ * @param value - The value to be verified as even.
2745+ * @returns {boolean} whether this value is even or not
2746+ * @constructor
2747+ */
2748+var ISEVEN = function (value) {
2749+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ISEVEN");
2750+    if (value === "") {
2751+        throw new Errors_1.ValueError("Function ISEVEN parameter 1 expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.");
2752+    }
2753+    var x = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2754+    return Math.floor(x) % 2 === 0;
2755+};
2756+exports.ISEVEN = ISEVEN;
2757+/**
2758+ * Checks whether the provided value is odd.
2759+ * @param value - The value to be verified as odd.
2760+ * @returns {boolean} whether this value is odd or not
2761+ * @constructor
2762+ */
2763+var ISODD = function (value) {
2764+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ISODD");
2765+    if (value === "") {
2766+        throw new Errors_1.ValueError("Function ISODD parameter 1 expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.");
2767+    }
2768+    var x = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2769+    return Math.floor(x) % 2 === 1;
2770+};
2771+exports.ISODD = ISODD;
2772+/**
2773+ * Returns the sine of an angle provided in radians.
2774+ * @param value - The angle to find the sine of, in radians.
2775+ * @returns {number} Sine of angle.
2776+ * @constructor
2777+ */
2778+var SIN = function (value) {
2779+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "SIN");
2780+    var rad = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2781+    return rad === Math.PI ? 0 : Math.sin(rad);
2782+};
2783+exports.SIN = SIN;
2784+/**
2785+ * Returns the hyperbolic sine of any real number.
2786+ * @param value - real number to find the hyperbolic sine of
2787+ * @returns {number} hyperbolic sine
2788+ * @constructor
2789+ */
2790+var SINH = function (value) {
2791+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "SINH");
2792+    var rad = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2793+    return Math["sinh"](rad);
2794+};
2795+exports.SINH = SINH;
2796+/**
2797+ * The value Pi.
2798+ * @returns {number} Pi.
2799+ * @constructor
2800+ */
2801+var PI = function () {
2802+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 0, "SINH");
2803+    return Math.PI;
2804+};
2805+exports.PI = PI;
2806+/**
2807+ * Returns the the logarithm of a number, base 10.
2808+ * @param value - The value for which to calculate the logarithm, base 10.
2809+ * @returns {number} logarithm of the number, in base 10.
2810+ * @constructor
2811+ */
2812+var LOG10 = function (value) {
2813+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "LOG10");
2814+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2815+    if (n < 1) {
2816+        throw new Errors_1.NumError("Function LOG10 parameter 1 value is " + n + ". It should be greater than 0.");
2817+    }
2818+    var ln = Math.log(n);
2819+    var lb = Math.log(10);
2820+    return ln / lb;
2821+};
2822+exports.LOG10 = LOG10;
2823+/**
2824+ * Returns the the logarithm of a number given a base.
2825+ * @param value - The value for which to calculate the logarithm given base.
2826+ * @param base - The base to use for calculation of the logarithm. Defaults to 10.
2827+ * @returns {number}
2828+ * @constructor
2829+ */
2830+var LOG = function (value, base) {
2831+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(arguments, 2, "LOG");
2832+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2833+    var b = TypeConverter_1.TypeConverter.firstValueAsNumber(base);
2834+    if (b < 1) {
2835+        throw new Errors_1.NumError("Function LOG parameter 2 value is " + b + ". It should be greater than 0.");
2836+    }
2837+    if (b < 2) {
2838+        throw new Errors_1.DivZeroError("Evaluation of function LOG caused a divide by zero error.");
2839+    }
2840+    var ln = Math.log(n);
2841+    var lb = Math.log(b);
2842+    if (lb === 0) {
2843+        throw new Errors_1.DivZeroError("Evaluation of function LOG caused a divide by zero error.");
2844+    }
2845+    return ln / lb;
2846+};
2847+exports.LOG = LOG;
2848+/**
2849+ * Returns the logarithm of a number, base e (Euler's number).
2850+ * @param value - The value for which to calculate the logarithm, base e.
2851+ * @returns {number} logarithm calculated
2852+ * @constructor
2853+ */
2854+var LN = function (value) {
2855+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "LN");
2856+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2857+    if (n < 1) {
2858+        throw new Errors_1.NumError("Function LN parameter 1 value is " + n + ". It should be greater than 0.");
2859+    }
2860+    return Math.log(n);
2861+};
2862+exports.LN = LN;
2863+/**
2864+ * Returns the tangent of an angle provided in radians.
2865+ * @param value - The angle to find the tangent of, in radians.
2866+ * @returns {number} tangent in radians
2867+ * @constructor
2868+ */
2869+var TAN = function (value) {
2870+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "TAN");
2871+    var rad = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2872+    return rad === Math.PI ? 0 : Math.tan(rad);
2873+};
2874+exports.TAN = TAN;
2875+/**
2876+ * Returns the hyperbolic tangent of any real number.
2877+ * @param value - Any real value to calculate the hyperbolic tangent of.
2878+ * @returns {number} hyperbolic tangent
2879+ * @constructor
2880+ */
2881+var TANH = function (value) {
2882+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "TANH");
2883+    var rad = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2884+    return Math["tanh"](rad);
2885+};
2886+exports.TANH = TANH;
2887+/**
2888+ * Rounds a number up to the nearest integer multiple of specified significance.
2889+ * @param value The value to round up to the nearest integer multiple of factor.
2890+ * @param factor - [ OPTIONAL ] The number to whose multiples value will be rounded.
2891+ * @returns {number}
2892+ * @constructor
2893+ */
2894+var CEILING = function (value, factor) {
2895+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "CEILING");
2896+    var num = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2897+    if (factor === undefined) {
2898+        return Math.ceil(num);
2899+    }
2900+    var significance = TypeConverter_1.TypeConverter.firstValueAsNumber(factor);
2901+    if (significance === 0) {
2902+        throw new Errors_1.DivZeroError("Function CEILING parameter 2 cannot be zero.");
2903+    }
2904+    var precision = -Math.floor(Math.log(significance) / Math.log(10));
2905+    if (num >= 0) {
2906+        return ROUND(Math.ceil(num / significance) * significance, precision);
2907+    }
2908+    else {
2909+        return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
2910+    }
2911+};
2912+exports.CEILING = CEILING;
2913+/**
2914+ * Rounds a number down to the nearest integer multiple of specified significance.
2915+ * @param value - The value to round down to the nearest integer multiple of factor.
2916+ * @param factor - The number to whose multiples value will be rounded.
2917+ * @returns {number}
2918+ * @constructor
2919+ */
2920+var FLOOR = function (value, factor) {
2921+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "FLOOR");
2922+    var num = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
2923+    if (factor === undefined) {
2924+        return Math.floor(num);
2925+    }
2926+    var significance = TypeConverter_1.TypeConverter.firstValueAsNumber(factor);
2927+    if (significance === 0) {
2928+        throw new Errors_1.DivZeroError("Function FLOOR parameter 2 cannot be zero.");
2929+    }
2930+    significance = significance ? Math.abs(significance) : 1;
2931+    var precision = -Math.floor(Math.log(significance) / Math.log(10));
2932+    if (num >= 0) {
2933+        return ROUND(Math.floor(num / significance) * significance, precision);
2934+    }
2935+    return -ROUND(Math.floor(Math.abs(num) / significance) * significance, precision);
2936+};
2937+exports.FLOOR = FLOOR;
2938+/**
2939+ * Returns one value if a logical expression is TRUE and another if it is FALSE.
2940+ * @param logicalExpression - An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE.
2941+ * @param valueIfTrue - The value the function returns if logical_expression is TRUE
2942+ * @param valueIfFalse - The value the function returns if logical_expression is FALSE.
2943+ * @returns one value if a logical expression is TRUE and another if it is FALSE.
2944+ * @constructor
2945+ */
2946+var IF = function (logicalExpression, valueIfTrue, valueIfFalse) {
2947+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "IF");
2948+    if (logicalExpression instanceof Array) {
2949+        if (logicalExpression.length === 0) {
2950+            throw new Errors_1.RefError("Reference does not exist.");
2951+        }
2952+        return IF(logicalExpression[0], valueIfTrue, valueIfFalse);
2953+    }
2954+    else if (logicalExpression === "") {
2955+        return valueIfFalse;
2956+    }
2957+    return (TypeConverter_1.TypeConverter.valueToBoolean(logicalExpression)) ? valueIfTrue : valueIfFalse;
2958+};
2959+exports.IF = IF;
2960+/**
2961+ * Returns a conditional count across a range.
2962+ * @param range - The range that is tested against criterion., value[1];
2963+ * @param criteria - The pattern or test to apply to range. If the range to check against contains text,
2964+ * this must be a string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string,
2965+ * in which * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing
2966+ * a ~ in front of them. If it is neither, it will compared with values in the range using equality comparison.
2967+ * @returns {number}
2968+ * @constructor
2969+ */
2970+var COUNTIF = function (range, criteria) {
2971+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "COUNTIF");
2972+    if (!(range instanceof Array)) {
2973+        range = [range];
2974+    }
2975+    var criteriaEvaluation = CriteriaFunctionFactory_1.CriteriaFunctionFactory.createCriteriaFunction(criteria);
2976+    var count = 0;
2977+    for (var i = 0; i < range.length; i++) {
2978+        var x = range[i];
2979+        if (x instanceof Array) {
2980+            count = count + COUNTIF.apply(this, [x, criteria]);
2981+        }
2982+        else if (criteriaEvaluation(x)) {
2983+            count++;
2984+        }
2985+    }
2986+    return count;
2987+};
2988+exports.COUNTIF = COUNTIF;
2989+/**
2990+ * Returns the count of a range depending on multiple criteria.
2991+ * @param values[0] criteria_range1 - The range to check against criterion1.
2992+ * @param values[1] criterion1 - The pattern or test to apply to criteria_range1.
2993+ * @param values[2...N] Repeated sets of ranges and criterion to check.
2994+ * @returns {number} count
2995+ * @constructor
2996+ */
2997+var COUNTIFS = function () {
2998+    var values = [];
2999+    for (var _i = 0; _i < arguments.length; _i++) {
3000+        values[_i] = arguments[_i];
3001+    }
3002+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 2, "COUNTIFS");
3003+    var criteriaEvaluationFunctions = values.map(function (criteria, index) {
3004+        if (index % 2 === 1) {
3005+            return CriteriaFunctionFactory_1.CriteriaFunctionFactory.createCriteriaFunction(criteria);
3006+        }
3007+        else {
3008+            return function () { return false; };
3009+        }
3010+    });
3011+    var filteredValues = [];
3012+    // Flatten arrays/ranges
3013+    for (var x = 0; x < values.length; x++) {
3014+        // If this is an array/range parameter
3015+        if (x % 2 === 0) {
3016+            filteredValues.push(Filter_1.Filter.flatten(values[x]));
3017+        }
3018+        else {
3019+            filteredValues.push(values[x]);
3020+        }
3021+    }
3022+    var count = 0;
3023+    // For every value in the range
3024+    for (var i = 0; i < filteredValues[0].length; i++) {
3025+        // Check for criteria eval for other ranges and other criteria pairs.
3026+        var otherCriteriaEvaluationSuccessfulSoFar = true;
3027+        for (var x = 0; x < filteredValues.length; x += 2) {
3028+            if (filteredValues[x].length < filteredValues[0].length) {
3029+                throw new Errors_1.ValueError("Array arguments to COUNTIFS are of different size.");
3030+            }
3031+            var criteriaEvaluation = criteriaEvaluationFunctions[x + 1];
3032+            if (otherCriteriaEvaluationSuccessfulSoFar) {
3033+                if (!criteriaEvaluation(filteredValues[x][i])) {
3034+                    otherCriteriaEvaluationSuccessfulSoFar = false;
3035+                }
3036+            }
3037+        }
3038+        if (otherCriteriaEvaluationSuccessfulSoFar) {
3039+            count++;
3040+        }
3041+    }
3042+    return count;
3043+};
3044+exports.COUNTIFS = COUNTIFS;
3045+/**
3046+ * Rounds a number to a certain number of decimal places according to standard rules.
3047+ * @param value - The value to round to places number of places.
3048+ * @param places - The number of decimal places to which to round.
3049+ * @returns {number}
3050+ * @constructor
3051+ */
3052+var ROUND = function (value, places) {
3053+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "ROUND");
3054+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3055+    var d = TypeConverter_1.TypeConverter.firstValueAsNumber(places);
3056+    return Math.round(n * Math.pow(10, d)) / Math.pow(10, d);
3057+};
3058+exports.ROUND = ROUND;
3059+/**
3060+ * Rounds a number to a certain number of decimal places, always rounding down to the next valid increment.
3061+ * @param value - The value to round to places number of places, always rounding down.
3062+ * @param places - (optional) The number of decimal places to which to round.
3063+ * @returns {number}
3064+ * @constructor
3065+ */
3066+var ROUNDDOWN = function (value, places) {
3067+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "ROUNDDOWN");
3068+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3069+    if (places === undefined) {
3070+        return Math.floor(n);
3071+    }
3072+    var d = TypeConverter_1.TypeConverter.firstValueAsNumber(places);
3073+    return Math.floor(n * Math.pow(10, d)) / Math.pow(10, d);
3074+};
3075+exports.ROUNDDOWN = ROUNDDOWN;
3076+/**
3077+ * Rounds a number to a certain number of decimal places, always rounding up to the next valid increment.
3078+ * @param value - The value to round to places number of places, always rounding up.
3079+ * @param places - (optional) The number of decimal places to which to round.
3080+ * @returns {number}
3081+ * @constructor
3082+ */
3083+var ROUNDUP = function (value, places) {
3084+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "ROUNDUP");
3085+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3086+    if (places === undefined) {
3087+        return Math.ceil(n);
3088+    }
3089+    var d = TypeConverter_1.TypeConverter.firstValueAsNumber(places);
3090+    return Math.ceil(n * Math.pow(10, d)) / Math.pow(10, d);
3091+};
3092+exports.ROUNDUP = ROUNDUP;
3093+/**
3094+ * Returns a conditional sum across a range.
3095+ * @param range -  The range which is tested against criterion.
3096+ * @param criteria - The pattern or test to apply to range. If the range to check against contains text, this must be a
3097+ * string. It can be a comparison based string (e.g. "=1", "<1", ">=1") or it can be a wild-card string, in which *
3098+ * matches any number of characters, and ? matches the next character. Both ? and * can be escaped by placing a ~ in
3099+ * front of them.
3100+ * @param sumRange - (optional) The range to be summed, if different from range.
3101+ * @returns {number}
3102+ * @constructor
3103+ */
3104+var SUMIF = function (range, criteria, sumRange) {
3105+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "SUMIF");
3106+    var criteriaEvaluation = CriteriaFunctionFactory_1.CriteriaFunctionFactory.createCriteriaFunction(criteria);
3107+    var sum = 0;
3108+    for (var i = 0; i < range.length; i++) {
3109+        var x = range[i];
3110+        if (x instanceof Array) {
3111+            sum += SUMIF.apply(this, [x, criteria]);
3112+        }
3113+        else {
3114+            if (sumRange && i > sumRange.length - 1) {
3115+                continue;
3116+            }
3117+            if (arguments.length === 2 && TypeConverter_1.TypeConverter.canCoerceToNumber(x) && criteriaEvaluation(x)) {
3118+                sum = sum + TypeConverter_1.TypeConverter.valueToNumber(x);
3119+            }
3120+            else if (arguments.length === 3 && TypeConverter_1.TypeConverter.canCoerceToNumber(sumRange[i]) && criteriaEvaluation(x)) {
3121+                sum = sum + TypeConverter_1.TypeConverter.valueToNumber(sumRange[i]);
3122+            }
3123+        }
3124+    }
3125+    return sum;
3126+};
3127+exports.SUMIF = SUMIF;
3128+/**
3129+ * Returns the sum of the squares of a series of numbers and/or cells.
3130+ * @param values  The values or range(s) whose squares to add together.
3131+ * @returns {number} the sum of the squares if the input.
3132+ * @constructor
3133+ */
3134+var SUMSQ = function () {
3135+    var values = [];
3136+    for (var _i = 0; _i < arguments.length; _i++) {
3137+        values[_i] = arguments[_i];
3138+    }
3139+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "SUMSQ");
3140+    var result = 0;
3141+    for (var i = 0; i < values.length; i++) {
3142+        if (values[i] instanceof Array) {
3143+            if (values[i].length === 0) {
3144+                throw new Errors_1.RefError("Reference does not exist.");
3145+            }
3146+            result = result + SUMSQ.apply(this, Filter_1.Filter.filterOutNonNumberValues(values[i]));
3147+        }
3148+        else {
3149+            var n = TypeConverter_1.TypeConverter.valueToNumber(values[i]);
3150+            result = result + (n * n);
3151+        }
3152+    }
3153+    return result;
3154+};
3155+exports.SUMSQ = SUMSQ;
3156+/**
3157+ * Truncates a number to a certain number of significant digits by omitting less significant digits.
3158+ * @param value - The value to be truncated.
3159+ * @param places - [ OPTIONAL - 0 by default ] - The number of significant digits to the right of the decimal point to
3160+ * retain. If places is greater than the number of significant digits in value, value is returned without modification.
3161+ * places may be negative, in which case the specified number of digits to the left of the decimal place are changed to
3162+ * zero. All digits to the right of the decimal place are discarded. If all digits of value are changed to zero, TRUNC
3163+ * simply returns 0.
3164+ * @returns {number} after truncation
3165+ * @constructor
3166+ */
3167+var TRUNC = function (value, places) {
3168+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "TRUNC");
3169+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3170+    var digits = 0;
3171+    if (places !== undefined) {
3172+        digits = TypeConverter_1.TypeConverter.firstValueAsNumber(places);
3173+    }
3174+    var sign = (n > 0) ? 1 : -1;
3175+    return sign * (Math.floor(Math.abs(n) * Math.pow(10, digits))) / Math.pow(10, digits);
3176+};
3177+exports.TRUNC = TRUNC;
3178+/**
3179+ * Converts an angle value in degrees to radians.
3180+ * @param angle - The angle to convert from degrees to radians.
3181+ * @returns {number} radians
3182+ * @constructor
3183+ */
3184+var RADIANS = function (angle) {
3185+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "RADIANS");
3186+    var d = TypeConverter_1.TypeConverter.firstValueAsNumber(angle);
3187+    return d * Math.PI / 180;
3188+};
3189+exports.RADIANS = RADIANS;
3190+/**
3191+ * Converts an angle value in radians to degrees.
3192+ * @param angle - The angle to convert from radians to degrees.
3193+ * @returns {number} degrees
3194+ * @constructor
3195+ */
3196+var DEGREES = function (angle) {
3197+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "DEGREES");
3198+    var r = TypeConverter_1.TypeConverter.firstValueAsNumber(angle);
3199+    return r * 180 / Math.PI;
3200+};
3201+exports.DEGREES = DEGREES;
3202+/**
3203+ * Returns the complementary Gauss error function of a value.
3204+ * @param value - The number for which to calculate the complementary Gauss error function.
3205+ * @returns {number} complementary Gauss error function of a value
3206+ * @constructor
3207+ */
3208+var ERFC = function (value) {
3209+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ERFC");
3210+    var v = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3211+    return v === 0 ? 1 : 1 - MathHelpers_1.erf(v);
3212+};
3213+exports.ERFC = ERFC;
3214+/**
3215+ * Returns the error function integrated between lower_limit and upper_limit.
3216+ * @param lowerLimit - The lower bound for integrating ERF.
3217+ * @param upperLimit - [Optional]. The upper bound for integrating ERF. If omitted, ERF integrates between
3218+ * zero and lower_limit.
3219+ * @returns {number} error function integrated between lower_limit and upper_limit
3220+ * @constructor
3221+ */
3222+var ERF = function (lowerLimit, upperLimit) {
3223+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "ERF");
3224+    var lower = TypeConverter_1.TypeConverter.firstValueAsNumber(lowerLimit);
3225+    var upper = upperLimit !== undefined ? TypeConverter_1.TypeConverter.firstValueAsNumber(upperLimit) : 0;
3226+    return upperLimit === undefined ? MathHelpers_1.erf(lower) : MathHelpers_1.erf(upper) - MathHelpers_1.erf(lower);
3227+};
3228+exports.ERF = ERF;
3229+/**
3230+ * Calculates the sum of the sums of the squares of values in two arrays.
3231+ * @param arrayX - The array or range of values whose squares will be added to the squares of corresponding
3232+ * entries in arrayY and added together.
3233+ * @param arrayY - The array or range of values whose squares will be added to the squares of corresponding
3234+ * entries in arrayX and added together.
3235+ * @returns {number} sum of the sums of the squares
3236+ * @constructor
3237+ */
3238+var SUMX2PY2 = function (arrayX, arrayY) {
3239+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "SUMX2PY2");
3240+    var arrOne = Filter_1.Filter.flattenAndThrow(arrayX);
3241+    var arrTwo = Filter_1.Filter.flattenAndThrow(arrayY);
3242+    if (arrOne.length !== arrTwo.length) {
3243+        throw new Errors_1.NAError("Array arguments to SUMX2PY2 are of different size.");
3244+    }
3245+    var result = 0;
3246+    for (var i = 0; i < arrOne.length; i++) {
3247+        // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
3248+        if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
3249+            result += arrOne[i] * arrOne[i] + arrTwo[i] * arrTwo[i];
3250+        }
3251+    }
3252+    return result;
3253+};
3254+exports.SUMX2PY2 = SUMX2PY2;
3255+/**
3256+ * Calculates the sum of the differences of the squares of values in two arrays.
3257+ * @param arrayX - The array or range of values whose squares will be reduced by the squares of corresponding
3258+ * entries in array_y and added together.
3259+ * @param arrayY - The array or range of values whose squares will be subtracted from the squares of
3260+ * corresponding entries in array_x and added together.
3261+ * @returns {number} sum of the differences of the squares
3262+ * @constructor
3263+ */
3264+var SUMX2MY2 = function (arrayX, arrayY) {
3265+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "SUMX2MY2");
3266+    var arrOne = Filter_1.Filter.flattenAndThrow(arrayX);
3267+    var arrTwo = Filter_1.Filter.flattenAndThrow(arrayY);
3268+    if (arrOne.length !== arrTwo.length) {
3269+        throw new Errors_1.NAError("Array arguments to SUMX2MY2 are of different size.");
3270+    }
3271+    var result = 0;
3272+    for (var i = 0; i < arrOne.length; i++) {
3273+        // If either values at this index are anything but numbers, skip them. This is the behavior in GS at least.
3274+        if (typeof arrOne[i] === "number" && typeof arrTwo[i] === "number") {
3275+            result += arrOne[i] * arrOne[i] - arrTwo[i] * arrTwo[i];
3276+        }
3277+    }
3278+    return result;
3279+};
3280+exports.SUMX2MY2 = SUMX2MY2;
3281+// Private function that will recursively generate an array of the unique primitives
3282+var _countUnique = function (values) {
3283+    var uniques = {};
3284+    for (var i = 0; i < values.length; i++) {
3285+        if (Array.isArray(values[i])) {
3286+            // For some reasons an empty range is converted to a range with a single empty string in it.
3287+            if (values[i].length === 0) {
3288+                values[i] = [""];
3289+            }
3290+            var uniquesOfArray = _countUnique(values[i]);
3291+            for (var key in uniquesOfArray) {
3292+                uniques[key] = true;
3293+            }
3294+        }
3295+        else {
3296+            uniques[Serializer_1.Serializer.serialize(values[i])] = true;
3297+        }
3298+    }
3299+    return uniques;
3300+};
3301+/**
3302+ * Counts the number of unique values in a list of specified values and ranges.
3303+ * @param values The values or ranges to consider for uniqueness. Supports an arbitrary number of arguments for this
3304+ * function.
3305+ * @returns {number} of unique values passed in.
3306+ * @constructor
3307+ */
3308+var COUNTUNIQUE = function () {
3309+    var values = [];
3310+    for (var _i = 0; _i < arguments.length; _i++) {
3311+        values[_i] = arguments[_i];
3312+    }
3313+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "COUNTUNIQUE");
3314+    var uniques = _countUnique(values);
3315+    return Object.keys(uniques).length;
3316+};
3317+exports.COUNTUNIQUE = COUNTUNIQUE;
3318+/**
3319+ * Calculates the sum of the products of corresponding entries in two equal-sized arrays or ranges.
3320+ * @param values Arrays or ranges whose entries will be multiplied with corresponding entries in the second such array
3321+ * or range.
3322+ * @returns {number} sum of the products
3323+ * @constructor
3324+ */
3325+var SUMPRODUCT = function () {
3326+    var values = [];
3327+    for (var _i = 0; _i < arguments.length; _i++) {
3328+        values[_i] = arguments[_i];
3329+    }
3330+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "SUMPRODUCT");
3331+    // Ensuring that all values are array values
3332+    for (var x = 0; x < values.length; x++) {
3333+        if (!Array.isArray(values[x])) {
3334+            values[x] = [values[x]];
3335+        }
3336+    }
3337+    // Flatten any nested ranges (arrays) and check for mismatched range sizes
3338+    var flattenedValues = [Filter_1.Filter.flattenAndThrow(values[0])];
3339+    for (var x = 1; x < values.length; x++) {
3340+        flattenedValues.push(Filter_1.Filter.flattenAndThrow(values[x]));
3341+        if (flattenedValues[x].length !== flattenedValues[0].length) {
3342+            throw new Errors_1.ValueError("SUMPRODUCT has mismatched range sizes. Expected count: "
3343+                + flattenedValues[0].length + ". Actual count: " + flattenedValues[0].length + ".");
3344+        }
3345+    }
3346+    // Do the actual math
3347+    var result = 0;
3348+    for (var i = 0; i < flattenedValues[0].length; i++) {
3349+        var product = 1;
3350+        for (var x = 0; x < flattenedValues.length; x++) {
3351+            product *= TypeConverter_1.TypeConverter.valueToNumberGracefully(flattenedValues[x][i]);
3352+        }
3353+        result += product;
3354+    }
3355+    return result;
3356+};
3357+exports.SUMPRODUCT = SUMPRODUCT;
3358+/**
3359+ * Returns the number of ways to choose some number of objects from a pool of a given size of objects.
3360+ * @param m - The size of the pool of objects to choose from.
3361+ * @param k - The number of objects to choose.
3362+ * @returns {number} number of ways
3363+ * @constructor
3364+ */
3365+var COMBIN = function (m, k) {
3366+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "COMBIN");
3367+    var MEMOIZED_FACT = [];
3368+    function fact(number) {
3369+        var n = Math.floor(number);
3370+        if (n === 0 || n === 1) {
3371+            return 1;
3372+        }
3373+        else if (MEMOIZED_FACT[n] > 0) {
3374+            return MEMOIZED_FACT[n];
3375+        }
3376+        else {
3377+            MEMOIZED_FACT[n] = fact(n - 1) * n;
3378+            return MEMOIZED_FACT[n];
3379+        }
3380+    }
3381+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(m);
3382+    var c = TypeConverter_1.TypeConverter.firstValueAsNumber(k);
3383+    if (n < c) {
3384+        throw new Errors_1.NumError("Function COMBIN parameter 2 value is "
3385+            + c + ". It should be less than or equal to value of Function COMBIN parameter 1 with " + n + ".");
3386+    }
3387+    n = Math.floor(n);
3388+    c = Math.floor(c);
3389+    var div = fact(c) * fact(n - c);
3390+    if (div === 0) {
3391+        throw new Errors_1.DivZeroError("Evaluation of function COMBIN caused a divide by zero error.");
3392+    }
3393+    return fact(n) / div;
3394+};
3395+exports.COMBIN = COMBIN;
3396diff --git a/dist/Formulas/Statistical.js b/dist/Formulas/Statistical.js
3397new file mode 100644
3398index 0000000..8ea559e
3399--- /dev/null
3400+++ b/dist/Formulas/Statistical.js
3401@@ -0,0 +1,529 @@
3402+"use strict";
3403+exports.__esModule = true;
3404+var ArgsChecker_1 = require("../Utilities/ArgsChecker");
3405+var CriteriaFunctionFactory_1 = require("../Utilities/CriteriaFunctionFactory");
3406+var Filter_1 = require("../Utilities/Filter");
3407+var TypeConverter_1 = require("../Utilities/TypeConverter");
3408+var Errors_1 = require("../Errors");
3409+var Math_1 = require("./Math");
3410+var MathHelpers_1 = require("../Utilities/MathHelpers");
3411+/**
3412+ * Calculates the sum of squares of deviations based on a sample.
3413+ * @param values - The values or ranges of the sample.
3414+ * @returns {number} sum of squares of deviations
3415+ * @constructor
3416+ */
3417+var DEVSQ = function () {
3418+    var values = [];
3419+    for (var _i = 0; _i < arguments.length; _i++) {
3420+        values[_i] = arguments[_i];
3421+    }
3422+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "DEVSQ");
3423+    var range = Filter_1.Filter.flattenAndThrow(values);
3424+    var result = 0;
3425+    var count = 0;
3426+    for (var i = 0; i < range.length; i++) {
3427+        result = result + TypeConverter_1.TypeConverter.valueToNumber(range[i]);
3428+        count++;
3429+    }
3430+    var mean = result / count;
3431+    var result = 0;
3432+    for (var i = 0; i < range.length; i++) {
3433+        result += Math.pow((TypeConverter_1.TypeConverter.valueToNumber(range[i]) - mean), 2);
3434+    }
3435+    return result;
3436+};
3437+exports.DEVSQ = DEVSQ;
3438+/**
3439+ * Returns the median value in a numeric dataset.
3440+ * @param values - The value(s) or range(s) to consider when calculating the median value.
3441+ * @returns {number} the median value of the dataset
3442+ * @constructor
3443+ */
3444+var MEDIAN = function () {
3445+    var values = [];
3446+    for (var _i = 0; _i < arguments.length; _i++) {
3447+        values[_i] = arguments[_i];
3448+    }
3449+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "MEDIAN");
3450+    var sortedArray = [];
3451+    values.forEach(function (currentValue) {
3452+        if (currentValue instanceof Array) {
3453+            if (currentValue.length === 0) {
3454+                throw new Errors_1.RefError("Reference does not exist.");
3455+            }
3456+            var filtered = Filter_1.Filter.filterOutStringValues(currentValue);
3457+            sortedArray = sortedArray.concat(filtered);
3458+        }
3459+        else {
3460+            sortedArray.push(TypeConverter_1.TypeConverter.valueToNumber(currentValue));
3461+        }
3462+    });
3463+    sortedArray = sortedArray.sort(function (a, b) {
3464+        var aN = TypeConverter_1.TypeConverter.valueToNumber(a);
3465+        var bN = TypeConverter_1.TypeConverter.valueToNumber(b);
3466+        return aN - bN;
3467+    });
3468+    if (sortedArray.length === 1) {
3469+        return TypeConverter_1.TypeConverter.valueToNumber(sortedArray[0]);
3470+    }
3471+    if (sortedArray.length === 0) {
3472+        throw new Errors_1.NumError("MEDIAN has no valid input data.");
3473+    }
3474+    // even number of values
3475+    if (sortedArray.length % 2 === 0) {
3476+        if (sortedArray.length === 2) {
3477+            return AVERAGE(sortedArray[0], sortedArray[1]);
3478+        }
3479+        var top = sortedArray[sortedArray.length / 2];
3480+        var bottom = sortedArray[(sortedArray.length / 2) - 1];
3481+        return AVERAGE(top, bottom);
3482+    }
3483+    else {
3484+        // odd number of values
3485+        return sortedArray[Math.round(sortedArray.length / 2) - 1];
3486+    }
3487+};
3488+exports.MEDIAN = MEDIAN;
3489+/**
3490+ * Returns the numerical average value in a dataset, ignoring text.
3491+ * @param values - The values or ranges to consider when calculating the average value.
3492+ * @returns {number} the average value of this dataset.
3493+ * @constructor
3494+ */
3495+var AVERAGE = function () {
3496+    var values = [];
3497+    for (var _i = 0; _i < arguments.length; _i++) {
3498+        values[_i] = arguments[_i];
3499+    }
3500+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "AVERAGE");
3501+    var result = 0;
3502+    var count = 0;
3503+    for (var i = 0; i < values.length; i++) {
3504+        if (values[i] instanceof Array) {
3505+            if (values[i].length === 0) {
3506+                throw new Errors_1.RefError("Reference does not exist.");
3507+            }
3508+            var filtered = Filter_1.Filter.filterOutStringValues(values[i]);
3509+            result = result + Math_1.SUM.apply(this, filtered);
3510+            count += filtered.length;
3511+        }
3512+        else {
3513+            result = result + TypeConverter_1.TypeConverter.valueToNumber(values[i]);
3514+            count++;
3515+        }
3516+    }
3517+    return result / count;
3518+};
3519+exports.AVERAGE = AVERAGE;
3520+/**
3521+ * Calculates the average of the magnitudes of deviations of data from a dataset's mean.
3522+ * @param values - The value(s) or range(s)
3523+ * @returns {number} average of the magnitudes of deviations of data from a dataset's mean
3524+ * @constructor
3525+ */
3526+var AVEDEV = function () {
3527+    var values = [];
3528+    for (var _i = 0; _i < arguments.length; _i++) {
3529+        values[_i] = arguments[_i];
3530+    }
3531+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "AVEDEV");
3532+    // Sort to array-values, and non-array-values
3533+    var arrayValues = [];
3534+    var nonArrayValues = [];
3535+    for (var i = 0; i < values.length; i++) {
3536+        var X = values[i];
3537+        if (X instanceof Array) {
3538+            if (X.length === 0) {
3539+                throw new Errors_1.RefError("Reference does not exist.");
3540+            }
3541+            arrayValues.push(X);
3542+        }
3543+        else {
3544+            nonArrayValues.push(TypeConverter_1.TypeConverter.valueToNumber(X));
3545+        }
3546+    }
3547+    // Remove string values from array-values, but not from non-array-values, and concat.
3548+    var flatValues = Filter_1.Filter.filterOutStringValues(Filter_1.Filter.flatten(arrayValues)).map(function (value) {
3549+        return TypeConverter_1.TypeConverter.valueToNumber(value);
3550+    }).concat(nonArrayValues);
3551+    // Calculating mean
3552+    var result = 0;
3553+    var count = 0;
3554+    for (var i = 0; i < flatValues.length; i++) {
3555+        result = result + TypeConverter_1.TypeConverter.valueToNumber(flatValues[i]);
3556+        count++;
3557+    }
3558+    if (count === 0) {
3559+        throw new Errors_1.DivZeroError("Evaluation of function AVEDEV caused a devide by zero error.");
3560+    }
3561+    var mean = result / count;
3562+    for (var i = 0; i < flatValues.length; i++) {
3563+        flatValues[i] = Math_1.ABS(TypeConverter_1.TypeConverter.valueToNumber(flatValues[i]) - mean);
3564+    }
3565+    return Math_1.SUM(flatValues) / flatValues.length;
3566+};
3567+exports.AVEDEV = AVEDEV;
3568+/**
3569+ * Returns the numerical average value in a dataset, coercing text values in ranges to 0 values.
3570+ * @param values - value(s) or range(s) to consider when calculating the average value.
3571+ * @returns {number} the numerical average value in a dataset
3572+ * @constructor
3573+ */
3574+var AVERAGEA = function () {
3575+    var values = [];
3576+    for (var _i = 0; _i < arguments.length; _i++) {
3577+        values[_i] = arguments[_i];
3578+    }
3579+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "AVERAGEA");
3580+    var result = 0;
3581+    var count = 0;
3582+    for (var i = 0; i < values.length; i++) {
3583+        if (values[i] instanceof Array) {
3584+            if (values[i].length === 0) {
3585+                throw new Errors_1.RefError("Reference does not exist.");
3586+            }
3587+            var filtered = Filter_1.Filter.stringValuesToZeros(values[i]);
3588+            result = result + Math_1.SUM.apply(this, filtered);
3589+            count += filtered.length;
3590+        }
3591+        else {
3592+            result = result + TypeConverter_1.TypeConverter.valueToNumber(values[i]);
3593+            count++;
3594+        }
3595+    }
3596+    if (count === 0) {
3597+        throw new Errors_1.DivZeroError("Evaluation of function AVEDEV caused a devide by zero error.");
3598+    }
3599+    return result / count;
3600+};
3601+exports.AVERAGEA = AVERAGEA;
3602+/**
3603+ * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
3604+ * will be ignored. CORREL is synonymous with PEARSON.
3605+ * @param dataY - The range representing the array or matrix of dependent data.
3606+ * @param dataX - The range representing the array or matrix of independent data.
3607+ * @returns {number} the Pearson product-moment correlation coefficient.
3608+ * @constructor
3609+ */
3610+var CORREL = function (dataY, dataX) {
3611+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "CORREL");
3612+    if (!Array.isArray(dataY)) {
3613+        dataY = [dataY];
3614+    }
3615+    if (!Array.isArray(dataX)) {
3616+        dataX = [dataX];
3617+    }
3618+    if (dataY.length !== dataX.length) {
3619+        throw new Errors_1.NAError("CORREL has mismatched argument count " + dataY + " vs " + dataX + ".");
3620+    }
3621+    var arr1 = Filter_1.Filter.filterOutNonNumberValues(Filter_1.Filter.flattenAndThrow(dataY));
3622+    var arr2 = Filter_1.Filter.filterOutNonNumberValues(Filter_1.Filter.flattenAndThrow(dataX));
3623+    var stdevArr1 = MathHelpers_1.stdev(arr1, 1);
3624+    var stdevArr2 = MathHelpers_1.stdev(arr2, 1);
3625+    if (stdevArr1 === 0 || stdevArr2 === 0) {
3626+        throw new Errors_1.DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
3627+    }
3628+    return MathHelpers_1.covariance(arr1, arr2) / stdevArr1 / stdevArr2;
3629+};
3630+exports.CORREL = CORREL;
3631+/**
3632+ * Calculates r, the Pearson product-moment correlation coefficient of a dataset. Any text encountered in the arguments
3633+ * will be ignored. PEARSON is synonymous with CORREL.
3634+ * @param dataY - The range representing the array or matrix of dependent data.
3635+ * @param dataX - The range representing the array or matrix of independent data.
3636+ * @returns {number} the Pearson product-moment correlation coefficient.
3637+ * @constructor
3638+ */
3639+var PEARSON = function (dataY, dataX) {
3640+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "PEARSON");
3641+    return CORREL.apply(this, [dataY, dataX]);
3642+};
3643+exports.PEARSON = PEARSON;
3644+/**
3645+ * Returns the value of the exponential distribution function with a specified lambda at a specified value.
3646+ * @param x - The input to the exponential distribution function. If cumulative is TRUE then EXPONDIST returns
3647+ * the cumulative probability of all values up to x.
3648+ * @param lambda - The lambda to specify the exponential distribution function.
3649+ * @param cumulative - Whether to use the exponential cumulative distribution.
3650+ * @returns {number} value of the exponential distribution function.
3651+ * @constructor
3652+ */
3653+var EXPONDIST = function (x, lambda, cumulative) {
3654+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "EXPONDIST");
3655+    function cdf(x, rate) {
3656+        return x < 0 ? 0 : 1 - Math.exp(-rate * x);
3657+    }
3658+    function pdf(x, rate) {
3659+        return x < 0 ? 0 : rate * Math.exp(-rate * x);
3660+    }
3661+    x = TypeConverter_1.TypeConverter.firstValueAsNumber(x);
3662+    lambda = TypeConverter_1.TypeConverter.firstValueAsNumber(lambda);
3663+    cumulative = TypeConverter_1.TypeConverter.firstValueAsBoolean(cumulative);
3664+    return (cumulative) ? cdf(x, lambda) : pdf(x, lambda);
3665+};
3666+exports.EXPONDIST = EXPONDIST;
3667+/**
3668+ * Calculates the left-tailed F probability distribution (degree of diversity) for two data sets with given input x.
3669+ * Alternately called Fisher-Snedecor distribution or Snecdor's F distribution.
3670+ * @param x - The input to the F probability distribution function. The value at which to evaluate the function.
3671+ * Must be a positive number.
3672+ * @param degreesFreedom1 - The numerator degrees of freedom.
3673+ * @param degreesFreedom2 - The denominator degrees of freedom.
3674+ * @param cumulative - Logical value that determines the form of the function. If true returns the cumulative
3675+ * distribution function. If false returns the probability density function.
3676+ * @returns {number|boolean} left-tailed F probability distribution
3677+ * @constructor
3678+ * TODO: This function should be stricter in its return type.
3679+ */
3680+var FDIST$LEFTTAILED = function (x, degreesFreedom1, degreesFreedom2, cumulative) {
3681+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 4, "FDIST$LEFTTAILED");
3682+    x = TypeConverter_1.TypeConverter.firstValueAsNumber(x);
3683+    if (x < 0) {
3684+        throw new Errors_1.NumError("Function F.DIST parameter 1 value is " + x + ". It should be greater than or equal to 0.");
3685+    }
3686+    var d1 = TypeConverter_1.TypeConverter.firstValueAsNumber(degreesFreedom1);
3687+    var d2 = TypeConverter_1.TypeConverter.firstValueAsNumber(degreesFreedom2);
3688+    var cum = TypeConverter_1.TypeConverter.firstValueAsBoolean(cumulative);
3689+    return (cum) ? MathHelpers_1.cdf(x, d1, d2) : MathHelpers_1.pdf(x, d1, d2);
3690+};
3691+exports.FDIST$LEFTTAILED = FDIST$LEFTTAILED;
3692+/**
3693+ * Returns the inverse of the (right-tailed) F probability distribution. If p = FDIST(x,...), then FINV(p,...) = x. The
3694+ * F distribution can be used in an F-test that compares the degree of variability in two data sets.
3695+ * @param probability - A probability associated with the F cumulative distribution.
3696+ * @param degFreedom1 - Required. The numerator degrees of freedom.
3697+ * @param degFreedom2 - Required. The denominator degrees of freedom.
3698+ * @returns {number} inverse of the (right-tailed) F probability distribution
3699+ * @constructor
3700+ */
3701+var FINV = function (probability, degFreedom1, degFreedom2) {
3702+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "FINV");
3703+    probability = TypeConverter_1.TypeConverter.firstValueAsNumber(probability);
3704+    if (probability <= 0.0 || probability > 1.0) {
3705+        throw new Errors_1.NumError("Function FINV parameter 1 value is " + probability
3706+            + ". It should be greater than or equal to 0, and less than 1.");
3707+    }
3708+    var d1 = TypeConverter_1.TypeConverter.firstValueAsNumber(degFreedom1);
3709+    var d2 = TypeConverter_1.TypeConverter.firstValueAsNumber(degFreedom2);
3710+    return MathHelpers_1.inv(1.0 - probability, d1, d2);
3711+};
3712+exports.FINV = FINV;
3713+/**
3714+ * Returns the Fisher transformation of a specified value.
3715+ * @param value - The value for which to calculate the Fisher transformation.
3716+ * @returns {number} Fisher transformation
3717+ * @constructor
3718+ */
3719+var FISHER = function (value) {
3720+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "FISHER");
3721+    var x = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3722+    if (x <= -1 || x >= 1) {
3723+        throw new Errors_1.NumError("Function FISHER parameter 1 value is " + x + ". Valid values are between -1 and 1 exclusive.");
3724+    }
3725+    return Math.log((1 + x) / (1 - x)) / 2;
3726+};
3727+exports.FISHER = FISHER;
3728+/**
3729+ * Returns the inverse Fisher transformation of a specified value.
3730+ * @param value - The value for which to calculate the inverse Fisher transformation.
3731+ * @returns {number} inverse Fisher transformation
3732+ * @constructor
3733+ */
3734+var FISHERINV = function (value) {
3735+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "FISHERINV");
3736+    var y = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3737+    var e2y = Math.exp(2 * y);
3738+    return (e2y - 1) / (e2y + 1);
3739+};
3740+exports.FISHERINV = FISHERINV;
3741+/**
3742+ * Returns the maximum value in a numeric dataset.
3743+ * @param values - The values or range(s) to consider when calculating the maximum value.
3744+ * @returns {number} the maximum value of the dataset
3745+ * @constructor
3746+ */
3747+var MAX = function () {
3748+    var values = [];
3749+    for (var _i = 0; _i < arguments.length; _i++) {
3750+        values[_i] = arguments[_i];
3751+    }
3752+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "MAX");
3753+    var maxSoFar = -Infinity;
3754+    for (var i = 0; i < values.length; i++) {
3755+        if (values[i] instanceof Array) {
3756+            if (values[i].length === 0) {
3757+                throw new Errors_1.RefError("Reference does not exist.");
3758+            }
3759+            var filtered = Filter_1.Filter.filterOutStringValues(values[i]);
3760+            if (filtered.length !== 0) {
3761+                maxSoFar = Math.max(MAX.apply(this, filtered), maxSoFar);
3762+            }
3763+        }
3764+        else {
3765+            maxSoFar = Math.max(TypeConverter_1.TypeConverter.valueToNumber(values[i]), maxSoFar);
3766+        }
3767+    }
3768+    return maxSoFar;
3769+};
3770+exports.MAX = MAX;
3771+/**
3772+ * Returns the maximum numeric value in a dataset.
3773+ * @param values - The value(s) or range(s) to consider when calculating the maximum value.
3774+ * @returns {number} maximum value of the dataset
3775+ * @constructor
3776+ */
3777+var MAXA = function () {
3778+    var values = [];
3779+    for (var _i = 0; _i < arguments.length; _i++) {
3780+        values[_i] = arguments[_i];
3781+    }
3782+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "MAXA");
3783+    var maxSoFar = -Infinity;
3784+    var filteredValues = Filter_1.Filter.stringValuesToZeros(values);
3785+    for (var i = 0; i < filteredValues.length; i++) {
3786+        if (filteredValues[i] instanceof Array) {
3787+            if (values[i].length === 0) {
3788+                throw new Errors_1.RefError("Reference does not exist.");
3789+            }
3790+            var filtered = Filter_1.Filter.stringValuesToZeros(filteredValues[i]);
3791+            if (filtered.length !== 0) {
3792+                maxSoFar = Math.max(MAXA.apply(this, filtered), maxSoFar);
3793+            }
3794+        }
3795+        else {
3796+            maxSoFar = Math.max(TypeConverter_1.TypeConverter.valueToNumber(filteredValues[i]), maxSoFar);
3797+        }
3798+    }
3799+    return maxSoFar;
3800+};
3801+exports.MAXA = MAXA;
3802+/**
3803+ * Returns the minimum value in a numeric dataset.
3804+ * @param values - The value(s) or range(s) to consider when calculating the minimum value.
3805+ * @returns {number} the minimum value of the dataset
3806+ * @constructor
3807+ */
3808+var MIN = function () {
3809+    var values = [];
3810+    for (var _i = 0; _i < arguments.length; _i++) {
3811+        values[_i] = arguments[_i];
3812+    }
3813+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "MIN");
3814+    var minSoFar = Infinity;
3815+    for (var i = 0; i < values.length; i++) {
3816+        if (values[i] instanceof Array) {
3817+            if (values[i].length === 0) {
3818+                throw new Errors_1.RefError("Reference does not exist.");
3819+            }
3820+            var filtered = Filter_1.Filter.filterOutStringValues(values[i]);
3821+            if (filtered.length !== 0) {
3822+                minSoFar = Math.min(MIN.apply(this, filtered), minSoFar);
3823+            }
3824+        }
3825+        else {
3826+            minSoFar = Math.min(TypeConverter_1.TypeConverter.valueToNumber(values[i]), minSoFar);
3827+        }
3828+    }
3829+    return minSoFar;
3830+};
3831+exports.MIN = MIN;
3832+/**
3833+ * Returns the minimum numeric value in a dataset.
3834+ * @param values - The value(s) or range(s) to consider when calculating the minimum value.
3835+ * @returns {number} the minimum value in the dataset
3836+ * @constructor
3837+ */
3838+var MINA = function () {
3839+    var values = [];
3840+    for (var _i = 0; _i < arguments.length; _i++) {
3841+        values[_i] = arguments[_i];
3842+    }
3843+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "MINA");
3844+    return MIN.apply(this, values);
3845+};
3846+exports.MINA = MINA;
3847+/**
3848+ * Returns the average of a range depending on criteria.
3849+ * @param criteriaRange - The range to check against criterion.
3850+ * @param criterion - The pattern or test to apply to criteria_range.
3851+ * @param averageRange - [optional] The range to average. If not included, criteria_range is used for the
3852+ * average instead.
3853+ * @returns {number}
3854+ * @constructor
3855+ * TODO: This needs to also accept a third parameter "average_range"
3856+ */
3857+var AVERAGEIF = function (criteriaRange, criterion, averageRange) {
3858+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "AVERAGEIF");
3859+    var range = Filter_1.Filter.flatten(criteriaRange);
3860+    var criteriaEvaluation = CriteriaFunctionFactory_1.CriteriaFunctionFactory.createCriteriaFunction(criterion);
3861+    var result = 0;
3862+    var count = 0;
3863+    for (var i = 0; i < range.length; i++) {
3864+        var val = TypeConverter_1.TypeConverter.valueToNumber(range[i]);
3865+        if (criteriaEvaluation(val)) {
3866+            result = result + val;
3867+            count++;
3868+        }
3869+    }
3870+    if (count === 0) {
3871+        throw new Errors_1.DivZeroError("Evaluation of function AVERAGEIF caused a divide by zero error.");
3872+    }
3873+    return result / count;
3874+};
3875+exports.AVERAGEIF = AVERAGEIF;
3876+/**
3877+ * Returns the a count of the number of numeric values in a dataset.
3878+ * @param values - The values or ranges to consider when counting.
3879+ * @returns {number} number of numeric values in a dataset.
3880+ * @constructor
3881+ */
3882+var COUNT = function () {
3883+    var values = [];
3884+    for (var _i = 0; _i < arguments.length; _i++) {
3885+        values[_i] = arguments[_i];
3886+    }
3887+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "COUNT");
3888+    var count = 0;
3889+    for (var i = 0; i < values.length; i++) {
3890+        if (values[i] instanceof Array) {
3891+            if (values[i].length > 0) {
3892+                count += COUNT.apply(this, values[i]);
3893+            }
3894+        }
3895+        else if (TypeConverter_1.TypeConverter.canCoerceToNumber(values[i])) {
3896+            count++;
3897+        }
3898+    }
3899+    return count;
3900+};
3901+exports.COUNT = COUNT;
3902+/**
3903+ * Returns the a count of the number of values in a dataset.
3904+ * @param values - The values or ranges to consider when counting.
3905+ * @returns {number} number of values in a dataset.
3906+ * @constructor
3907+ */
3908+var COUNTA = function () {
3909+    var values = [];
3910+    for (var _i = 0; _i < arguments.length; _i++) {
3911+        values[_i] = arguments[_i];
3912+    }
3913+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "COUNTA");
3914+    var count = 0;
3915+    for (var i = 0; i < values.length; i++) {
3916+        if (values[i] instanceof Array) {
3917+            if (values[i].length > 0) {
3918+                count += COUNTA.apply(this, values[i]);
3919+            }
3920+            else {
3921+                count++;
3922+            }
3923+        }
3924+        else {
3925+            count++;
3926+        }
3927+    }
3928+    return count;
3929+};
3930+exports.COUNTA = COUNTA;
3931diff --git a/dist/Formulas/Text.js b/dist/Formulas/Text.js
3932new file mode 100644
3933index 0000000..2f3bdef
3934--- /dev/null
3935+++ b/dist/Formulas/Text.js
3936@@ -0,0 +1,410 @@
3937+"use strict";
3938+exports.__esModule = true;
3939+var ArgsChecker_1 = require("../Utilities/ArgsChecker");
3940+var TypeConverter_1 = require("../Utilities/TypeConverter");
3941+var Errors_1 = require("../Errors");
3942+/**
3943+ * Computes the value of a Roman numeral.
3944+ * @param text - The Roman numeral to format, whose value must be between 1 and 3999, inclusive.
3945+ * @returns {number} value in integer format
3946+ * @constructor
3947+ */
3948+var ARABIC = function (text) {
3949+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ARABIC");
3950+    if (typeof text !== "string") {
3951+        throw new Errors_1.ValueError('Invalid roman numeral in ARABIC evaluation.');
3952+    }
3953+    var negative = false;
3954+    if (text[0] === "-") {
3955+        negative = true;
3956+        text = text.substr(1);
3957+    }
3958+    // Credits: Rafa? Kukawski
3959+    if (!/^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/.test(text)) {
3960+        throw new Errors_1.ValueError('Invalid roman numeral in ARABIC evaluation.');
3961+    }
3962+    var r = 0;
3963+    text.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g, function (i) {
3964+        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];
3965+    });
3966+    if (negative) {
3967+        return r * -1;
3968+    }
3969+    return r;
3970+};
3971+exports.ARABIC = ARABIC;
3972+/**
3973+ * Convert a number into a character according to the current Unicode table.
3974+ * @param value - The number of the character to look up from the current Unicode table in decimal format.
3975+ * @returns {string} character corresponding to Unicode number
3976+ * @constructor
3977+ */
3978+var CHAR = function (value) {
3979+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "CHAR");
3980+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
3981+    if (n < 1 || n > 1114112) {
3982+        throw new Errors_1.NumError("Function CHAR parameter 1 value " + n + " is out of range.");
3983+    }
3984+    return String.fromCharCode(n);
3985+};
3986+exports.CHAR = CHAR;
3987+/**
3988+ * Returns the numeric Unicode map value of the first character in the string provided.
3989+ * @param value - The string whose first character's Unicode map value will be returned.
3990+ * @returns {number} number of the first character's Unicode value
3991+ * @constructor
3992+ */
3993+var CODE = function (value) {
3994+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "CODE");
3995+    var text = TypeConverter_1.TypeConverter.firstValueAsString(value);
3996+    if (text === "") {
3997+        throw new Errors_1.ValueError("Function CODE parameter 1 value should be non-empty.");
3998+    }
3999+    return text.charCodeAt(0);
4000+};
4001+exports.CODE = CODE;
4002+/**
4003+ * Divides text around a specified character or string, and puts each fragment into a separate cell in the row.
4004+ * @param text - The text to divide.
4005+ * @param delimiter - The character or characters to use to split text.
4006+ * @param splitByEach - [optional] Whether or not to divide text around each character contained in
4007+ * delimiter.
4008+ * @returns {Array<string>} containing the split
4009+ * @constructor
4010+ * TODO: At some point this needs to return a more complex type than Array. Needs to return a type that has a dimension.
4011+ */
4012+var SPLIT = function (text, delimiter, splitByEach) {
4013+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "SPLIT");
4014+    text = TypeConverter_1.TypeConverter.firstValueAsString(text);
4015+    delimiter = TypeConverter_1.TypeConverter.firstValueAsString(delimiter);
4016+    splitByEach = splitByEach === undefined ? false : TypeConverter_1.TypeConverter.firstValueAsBoolean(splitByEach);
4017+    if (splitByEach) {
4018+        var result = [text];
4019+        for (var i = 0; i < delimiter.length; i++) {
4020+            var char = delimiter[i];
4021+            var subResult = [];
4022+            for (var x = 0; x < result.length; x++) {
4023+                subResult = subResult.concat(result[x].split(char));
4024+            }
4025+            result = subResult;
4026+        }
4027+        return result.filter(function (val) {
4028+            return val.trim() !== "";
4029+        });
4030+    }
4031+    else {
4032+        return text.split(delimiter);
4033+    }
4034+};
4035+exports.SPLIT = SPLIT;
4036+/**
4037+ * Appends strings to one another.
4038+ * @param values - to append to one another. Must contain at least one value
4039+ * @returns {string} concatenated string
4040+ * @constructor
4041+ */
4042+var CONCATENATE = function () {
4043+    var values = [];
4044+    for (var _i = 0; _i < arguments.length; _i++) {
4045+        values[_i] = arguments[_i];
4046+    }
4047+    ArgsChecker_1.ArgsChecker.checkAtLeastLength(values, 1, "CONCATENATE");
4048+    var string = '';
4049+    for (var i = 0; i < values.length; i++) {
4050+        if (values[i] instanceof Array) {
4051+            if (values[i].length === 0) {
4052+                throw new Errors_1.RefError("Reference does not exist.");
4053+            }
4054+            string += CONCATENATE.apply(this, arguments[i]);
4055+        }
4056+        else {
4057+            string += TypeConverter_1.TypeConverter.valueToString(values[i]);
4058+        }
4059+    }
4060+    return string;
4061+};
4062+exports.CONCATENATE = CONCATENATE;
4063+/**
4064+ * Converts a numeric value to a different unit of measure.
4065+ * @param value - the numeric value in start_unit to convert to end_unit.
4066+ * @param startUnit - The starting unit, the unit currently assigned to value.
4067+ * @param endUnit - The unit of measure into which to convert value.
4068+ * @returns {number}
4069+ * @constructor
4070+ * TODO: Looking up units is not efficient at all. We should use an object instead of iterating through an array.
4071+ */
4072+var CONVERT = function (value, startUnit, endUnit) {
4073+    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "CONVERT");
4074+    var n = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
4075+    var fromUnit = TypeConverter_1.TypeConverter.firstValueAsString(startUnit);
4076+    var toUnit = TypeConverter_1.TypeConverter.firstValueAsString(endUnit);
4077+    // NOTE: A lot of the code for this method is from https://github.com/sutoiku/formula.js. I'm relying on them to have
4078+    // gotten it right, but I'm spot checking some of their work against GS, MSE, LibreOffice, OpenOffice.
4079+    // List of units supported by CONVERT and units defined by the International System of Units
4080+    // [Name, Symbol, Alternate symbols, Quantity, ISU, CONVERT, Conversion ratio]
4081+    var units = [
4082+        ["a.u. of action", "?", null, "action", false, false, 1.05457168181818e-34],
4083+        ["a.u. of charge", "e", null, "electric_charge", false, false, 1.60217653141414e-19],
4084+        ["a.u. of energy", "Eh", null, "energy", false, false, 4.35974417757576e-18],
4085+        ["a.u. of length", "a?", null, "length", false, false, 5.29177210818182e-11],
4086+        ["a.u. of mass", "m?", null, "mass", false, false, 9.10938261616162e-31],
4087+        ["a.u. of time", "?/Eh", null, "time", false, false, 2.41888432650516e-17],
4088+        ["admiralty knot", "admkn", null, "speed", false, true, 0.514773333],
4089+        ["ampere", "A", null, "electric_current", true, false, 1],
4090+        ["ampere per meter", "A/m", null, "magnetic_field_intensity", true, false, 1],
4091+        ["ångström", "Å", ["ang"], "length", false, true, 1e-10],
4092+        ["are", "ar", null, "area", false, true, 100],
4093+        ["astronomical unit", "ua", null, "length", false, false, 1.49597870691667e-11],
4094+        ["bar", "bar", null, "pressure", false, false, 100000],
4095+        ["barn", "b", null, "area", false, false, 1e-28],
4096+        ["becquerel", "Bq", null, "radioactivity", true, false, 1],
4097+        ["bit", "bit", ["b"], "information", false, true, 1],
4098+        ["btu", "BTU", ["btu"], "energy", false, true, 1055.05585262],
4099+        ["byte", "byte", null, "information", false, true, 8],
4100+        ["candela", "cd", null, "luminous_intensity", true, false, 1],
4101+        ["candela per square metre", "cd/m?", null, "luminance", true, false, 1],
4102+        ["coulomb", "C", null, "electric_charge", true, false, 1],
4103+        ["cubic ångström", "ang3", ["ang^3"], "volume", false, true, 1e-30],
4104+        ["cubic foot", "ft3", ["ft^3"], "volume", false, true, 0.028316846592],
4105+        ["cubic inch", "in3", ["in^3"], "volume", false, true, 0.000016387064],
4106+        ["cubic light-year", "ly3", ["ly^3"], "volume", false, true, 8.46786664623715e-47],
4107+        ["cubic metre", "m?", null, "volume", true, true, 1],
4108+        ["cubic mile", "mi3", ["mi^3"], "volume", false, true, 4168181825.44058],
4109+        ["cubic nautical mile", "Nmi3", ["Nmi^3"], "volume", false, true, 6352182208],
4110+        ["cubic Pica", "Pica3", ["Picapt3", "Pica^3", "Picapt^3"], "volume", false, true, 7.58660370370369e-8],
4111+        ["cubic yard", "yd3", ["yd^3"], "volume", false, true, 0.764554857984],
4112+        ["cup", "cup", null, "volume", false, true, 0.0002365882365],
4113+        ["dalton", "Da", ["u"], "mass", false, false, 1.66053886282828e-27],
4114+        ["day", "d", ["day"], "time", false, true, 86400],
4115+        ["degree", "°", null, "angle", false, false, 0.0174532925199433],
4116+        ["degrees Rankine", "Rank", null, "temperature", false, true, 0.555555555555556],
4117+        ["dyne", "dyn", ["dy"], "force", false, true, 0.00001],
4118+        ["electronvolt", "eV", ["ev"], "energy", false, true, 1.60217656514141],
4119+        ["ell", "ell", null, "length", false, true, 1.143],
4120+        ["erg", "erg", ["e"], "energy", false, true, 1e-7],
4121+        ["farad", "F", null, "electric_capacitance", true, false, 1],
4122+        ["fluid ounce", "oz", null, "volume", false, true, 0.0000295735295625],
4123+        ["foot", "ft", null, "length", false, true, 0.3048],
4124+        ["foot-pound", "flb", null, "energy", false, true, 1.3558179483314],
4125+        ["gal", "Gal", null, "acceleration", false, false, 0.01],
4126+        ["gallon", "gal", null, "volume", false, true, 0.003785411784],
4127+        ["gauss", "G", ["ga"], "magnetic_flux_density", false, true, 1],
4128+        ["grain", "grain", null, "mass", false, true, 0.0000647989],
4129+        ["gram", "g", null, "mass", false, true, 0.001],
4130+        ["gray", "Gy", null, "absorbed_dose", true, false, 1],
4131+        ["gross registered ton", "GRT", ["regton"], "volume", false, true, 2.8316846592],
4132+        ["hectare", "ha", null, "area", false, true, 10000],
4133+        ["henry", "H", null, "inductance", true, false, 1],
4134+        ["hertz", "Hz", null, "frequency", true, false, 1],
4135+        ["horsepower", "HP", ["h"], "power", false, true, 745.69987158227],
4136+        ["horsepower-hour", "HPh", ["hh", "hph"], "energy", false, true, 2684519.538],
4137+        ["hour", "h", ["hr"], "time", false, true, 3600],
4138+        ["imperial gallon (U.K.)", "uk_gal", null, "volume", false, true, 0.00454609],
4139+        ["imperial hundredweight", "lcwt", ["uk_cwt", "hweight"], "mass", false, true, 50.802345],
4140+        ["imperial quart (U.K)", "uk_qt", null, "volume", false, true, 0.0011365225],
4141+        ["imperial ton", "brton", ["uk_ton", "LTON"], "mass", false, true, 1016.046909],
4142+        ["inch", "in", null, "length", false, true, 0.0254],
4143+        ["international acre", "uk_acre", null, "area", false, true, 4046.8564224],
4144+        ["IT calorie", "cal", null, "energy", false, true, 4.1868],
4145+        ["joule", "J", null, "energy", true, true, 1],
4146+        ["katal", "kat", null, "catalytic_activity", true, false, 1],
4147+        ["kelvin", "K", ["kel"], "temperature", true, true, 1],
4148+        ["kilogram", "kg", null, "mass", true, true, 1],
4149+        ["knot", "kn", null, "speed", false, true, 0.514444444444444],
4150+        ["light-year", "ly", null, "length", false, true, 9460730472580800],
4151+        ["litre", "L", ["l", "lt"], "volume", false, true, 0.001],
4152+        ["lumen", "lm", null, "luminous_flux", true, false, 1],
4153+        ["lux", "lx", null, "illuminance", true, false, 1],
4154+        ["maxwell", "Mx", null, "magnetic_flux", false, false, 1e-18],
4155+        ["measurement ton", "MTON", null, "volume", false, true, 1.13267386368],
4156+        ["meter per hour", "m/h", ["m/hr"], "speed", false, true, 0.00027777777777778],
4157+        ["meter per second", "m/s", ["m/sec"], "speed", true, true, 1],
4158+        ["meter per second squared", "m?s??", null, "acceleration", true, false, 1],
4159+        ["parsec", "pc", ["parsec"], "length", false, true, 30856775814671900],
4160+        ["meter squared per second", "m?/s", null, "kinematic_viscosity", true, false, 1],
4161+        ["metre", "m", null, "length", true, true, 1],
4162+        ["miles per hour", "mph", null, "speed", false, true, 0.44704],
4163+        ["millimetre of mercury", "mmHg", null, "pressure", false, false, 133.322],
4164+        ["minute", "?", null, "angle", false, false, 0.000290888208665722],
4165+        ["minute", "min", ["mn"], "time", false, true, 60],
4166+        ["modern teaspoon", "tspm", null, "volume", false, true, 0.000005],
4167+        ["mole", "mol", null, "amount_of_substance", true, false, 1],
4168+        ["morgen", "Morgen", null, "area", false, true, 2500],
4169+        ["n.u. of action", "?", null, "action", false, false, 1.05457168181818e-34],
4170+        ["n.u. of mass", "m?", null, "mass", false, false, 9.10938261616162e-31],
4171+        ["n.u. of speed", "c?", null, "speed", false, false, 299792458],
4172+        ["n.u. of time", "?/(me?c??)", null, "time", false, false, 1.28808866778687e-21],
4173+        ["nautical mile", "M", ["Nmi"], "length", false, true, 1852],
4174+        ["newton", "N", null, "force", true, true, 1],
4175+        ["œrsted", "Oe ", null, "magnetic_field_intensity", false, false, 79.5774715459477],
4176+        ["ohm", "Ω", null, "electric_resistance", true, false, 1],
4177+        ["ounce mass", "ozm", null, "mass", false, true, 0.028349523125],
4178+        ["pascal", "Pa", null, "pressure", true, false, 1],
4179+        ["pascal second", "Pa?s", null, "dynamic_viscosity", true, false, 1],
4180+        ["pferdestärke", "PS", null, "power", false, true, 735.49875],
4181+        ["phot", "ph", null, "illuminance", false, false, 0.0001],
4182+        ["pica (1/6 inch)", "pica", null, "length", false, true, 0.00035277777777778],
4183+        ["pica (1/72 inch)", "Pica", ["Picapt"], "length", false, true, 0.00423333333333333],
4184+        ["poise", "P", null, "dynamic_viscosity", false, false, 0.1],
4185+        ["pond", "pond", null, "force", false, true, 0.00980665],
4186+        ["pound force", "lbf", null, "force", false, true, 4.4482216152605],
4187+        ["pound mass", "lbm", null, "mass", false, true, 0.45359237],
4188+        ["quart", "qt", null, "volume", false, true, 0.000946352946],
4189+        ["radian", "rad", null, "angle", true, false, 1],
4190+        ["second", "?", null, "angle", false, false, 0.00000484813681109536],
4191+        ["second", "s", ["sec"], "time", true, true, 1],
4192+        ["short hundredweight", "cwt", ["shweight"], "mass", false, true, 45.359237],
4193+        ["siemens", "S", null, "electrical_conductance", true, false, 1],
4194+        ["sievert", "Sv", null, "equivalent_dose", true, false, 1],
4195+        ["slug", "sg", null, "mass", false, true, 14.59390294],
4196+        ["square ångström", "ang2", ["ang^2"], "area", false, true, 1e-20],
4197+        ["square foot", "ft2", ["ft^2"], "area", false, true, 0.09290304],
4198+        ["square inch", "in2", ["in^2"], "area", false, true, 0.00064516],
4199+        ["square light-year", "ly2", ["ly^2"], "area", false, true, 8.95054210748189e+31],
4200+        ["square meter", "m?", null, "area", true, true, 1],
4201+        ["square meter", "m^2", null, "area", true, true, 1],
4202+        ["square mile", "mi2", ["mi^2"], "area", false, true, 2589988.110336],
4203+        ["square nautical mile", "Nmi2", ["Nmi^2"], "area", false, true, 3429904],
4204+        ["square Pica", "Pica2", ["Picapt2", "Pica^2", "Picapt^2"], "area", false, true, 0.00001792111111111],
4205+        ["square yard", "yd2", ["yd^2"], "area", false, true, 0.83612736],
4206+        ["statute mile", "mi", null, "length", false, true, 1609.344],
4207+        ["steradian", "sr", null, "solid_angle", true, false, 1],
4208+        ["stilb", "sb", null, "luminance", false, false, 0.0001],
4209+        ["stokes", "St", null, "kinematic_viscosity", false, false, 0.0001],
4210+        ["stone", "stone", null, "mass", false, true, 6.35029318],
4211+        ["tablespoon", "tbs", null, "volume", false, true, 0.0000147868],
4212+        ["teaspoon", "tsp", null, "volume", false, true, 0.00000492892],
4213+        ["tesla", "T", null, "magnetic_flux_density", true, true, 1],
4214+        ["thermodynamic calorie", "c", null, "energy", false, true, 4.184],
4215+        ["ton", "ton", null, "mass", false, true, 907.18474],
4216+        ["tonne", "t", null, "mass", false, false, 1000],
4217+        ["U.K. pint", "uk_pt", null, "volume", false, true, 0.00056826125],
4218+        ["U.S. bushel", "bushel", null, "volume", false, true, 0.03523907],
4219+        ["U.S. oil barrel", "barrel", null, "volume", false, true, 0.158987295],
4220+        ["U.S. pint", "pt", ["us_pt"], "volume", false, true, 0.000473176473],
4221+        ["U.S. survey mile", "survey_mi", null, "length", false, true, 1609.347219],
4222+        ["U.S. survey/statute acre", "us_acre", null, "area", false, true, 4046.87261],
4223+        ["volt", "V", null, "voltage", true, false, 1],
4224+        ["watt", "W", null, "power", true, true, 1],
4225+        ["watt-hour", "Wh", ["wh"], "energy", false, true, 3600],
4226+        ["weber", "Wb", null, "magnetic_flux", true, false, 1],
4227+        ["yard", "yd", null, "length", false, true, 0.9144],
4228+        ["year", "yr", null, "time", false, true, 31557600]
4229+    ];
4230+    // Binary prefixes
4231+    // [Name, Prefix power of 2 value, Previx value, Abbreviation, Derived from]
4232+    var binary_prefixes = {
4233+        Yi: ["yobi", 80, 1208925819614629174706176, "Yi", "yotta"],
4234+        Zi: ["zebi", 70, 1180591620717411303424, "Zi", "zetta"],
4235+        Ei: ["exbi", 60, 1152921504606846976, "Ei", "exa"],
4236+        Pi: ["pebi", 50, 1125899906842624, "Pi", "peta"],
4237+        Ti: ["tebi", 40, 1099511627776, "Ti", "tera"],
4238+        Gi: ["gibi", 30, 1073741824, "Gi", "giga"],
4239+        Mi: ["mebi", 20, 1048576, "Mi", "mega"],
4240+        ki: ["kibi", 10, 1024, "ki", "kilo"]
4241+    };
4242+    // Unit prefixes
4243+    // [Name, Multiplier, Abbreviation]
4244+    var unit_prefixes = {
4245+        Y: ["yotta", 1e+24, "Y"],
4246+        Z: ["zetta", 1e+21, "Z"],
4247+        E: ["exa", 1e+18, "E"],
4248+        P: ["peta", 1e+15, "P"],
4249+        T: ["tera", 1e+12, "T"],
4250+        G: ["giga", 1e+09, "G"],
4251+        M: ["mega", 1e+06, "M"],
4252+        k: ["kilo", 1e+03, "k"],
4253+        h: ["hecto", 1e+02, "h"],
4254+        e: ["dekao", 1e+01, "e"],
4255+        d: ["deci", 1e-01, "d"],
4256+        c: ["centi", 1e-02, "c"],
4257+        m: ["milli", 1e-03, "m"],
4258+        u: ["micro", 1e-06, "u"],
4259+        n: ["nano", 1e-09, "n"],
4260+        p: ["pico", 1e-12, "p"],
4261+        f: ["femto", 1e-15, "f"],
4262+        a: ["atto", 1e-18, "a"],
4263+        z: ["zepto", 1e-21, "z"],
4264+        y: ["yocto", 1e-24, "y"]
4265+    };
4266+    // Initialize units and multipliers
4267+    var from = null;
4268+    var to = null;
4269+    var base_from_unit = fromUnit;
4270+    var base_to_unit = toUnit;
4271+    var from_multiplier = 1;
4272+    var to_multiplier = 1;
4273+    var alt;
4274+    // Lookup from and to units
4275+    for (var i = 0; i < units.length; i++) {
4276+        alt = (units[i][2] === null) ? [] : units[i][2];
4277+        if (units[i][1] === base_from_unit || alt.indexOf(base_from_unit) >= 0) {
4278+            from = units[i];
4279+        }
4280+        if (units[i][1] === base_to_unit || alt.indexOf(base_to_unit) >= 0) {
4281+            to = units[i];
4282+        }
4283+    }
4284+    // Lookup from prefix
4285+    if (from === null) {
4286+        var from_binary_prefix = binary_prefixes[fromUnit.substring(0, 2)];
4287+        var from_unit_prefix = unit_prefixes[fromUnit.substring(0, 1)];
4288+        // Handle dekao unit prefix (only unit prefix with two characters)
4289+        if (fromUnit.substring(0, 2) === 'da') {
4290+            from_unit_prefix = ["dekao", 1e+01, "da"];
4291+        }
4292+        // Handle binary prefixes first (so that 'Yi' is processed before 'Y')
4293+        if (from_binary_prefix) {
4294+            from_multiplier = from_binary_prefix[2];
4295+            base_from_unit = fromUnit.substring(2);
4296+        }
4297+        else if (from_unit_prefix) {
4298+            from_multiplier = from_unit_prefix[1];
4299+            base_from_unit = fromUnit.substring(from_unit_prefix[2].length);
4300+        }
4301+        // Lookup from unit
4302+        for (var j = 0; j < units.length; j++) {
4303+            alt = (units[j][2] === null) ? [] : units[j][2];
4304+            if (units[j][1] === base_from_unit || alt.indexOf(base_from_unit) >= 0) {
4305+                from = units[j];
4306+            }
4307+        }
4308+    }
4309+    // Lookup to prefix
4310+    if (to === null) {
4311+        var to_binary_prefix = binary_prefixes[toUnit.substring(0, 2)];
4312+        var to_unit_prefix = unit_prefixes[toUnit.substring(0, 1)];
4313+        // Handle dekao unit prefix (only unit prefix with two characters)
4314+        if (toUnit.substring(0, 2) === 'da') {
4315+            to_unit_prefix = ["dekao", 1e+01, "da"];
4316+        }
4317+        // Handle binary prefixes first (so that 'Yi' is processed before 'Y')
4318+        if (to_binary_prefix) {
4319+            to_multiplier = to_binary_prefix[2];
4320+            base_to_unit = toUnit.substring(2);
4321+        }
4322+        else if (to_unit_prefix) {
4323+            to_multiplier = to_unit_prefix[1];
4324+            base_to_unit = toUnit.substring(to_unit_prefix[2].length);
4325+        }
4326+        // Lookup to unit
4327+        for (var k = 0; k < units.length; k++) {
4328+            alt = (units[k][2] === null) ? [] : units[k][2];
4329+            if (units[k][1] === base_to_unit || alt.indexOf(base_to_unit) >= 0) {
4330+                to = units[k];
4331+            }
4332+        }
4333+    }
4334+    // Return error if a unit does not exist
4335+    if (from === null || to === null) {
4336+        console.log(from, to);
4337+        throw new Errors_1.NAError("Invalid units for conversion.");
4338+    }
4339+    // Return error if units represent different quantities
4340+    if (from[3] !== to[3]) {
4341+        throw new Errors_1.NAError("Invalid units for conversion.");
4342+    }
4343+    // Return converted number
4344+    return n * from[6] * from_multiplier / (to[6] * to_multiplier);
4345+};
4346+exports.CONVERT = CONVERT;
4347diff --git a/dist/Sheet.js b/dist/Sheet.js
4348new file mode 100644
4349index 0000000..b135c2c
4350--- /dev/null
4351+++ b/dist/Sheet.js
4352@@ -0,0 +1,509 @@
4353+"use strict";
4354+exports.__esModule = true;
4355+/// <reference path="parser.d.ts"/>
4356+var Parser_1 = require("./Parser");
4357+var Cell_1 = require("./Cell");
4358+var Errors_1 = require("./Errors");
4359+var Formulas_1 = require("./Formulas");
4360+var AllFormulas = require("./Formulas/AllFormulas");
4361+exports.AllFormulas = AllFormulas;
4362+var TypeConverter_1 = require("./Utilities/TypeConverter");
4363+/**
4364+ * Model representing a spreadsheet. When values/cells are added, dependencies recalculated, and true-values of those
4365+ * cells will be updated.
4366+ */
4367+var Sheet = (function () {
4368+    var instance = this;
4369+    // Will be overwritten, but needs to be initialized, and have some functions for tsc compilation.
4370+    var parser = {
4371+        setObj: function (obj) { },
4372+        parse: function (formula) { }
4373+    };
4374+    /**
4375+     * Creates a new FormulaParser, which parses formulas, and does minimal error handling.
4376+     *
4377+     * @param handler should be this instance. Needs access to helper.fixedCellValue, helper.cellValue,
4378+     * helper.cellRangeValue, and helper.fixedCellRangeValue
4379+     * @returns formula parser instance for use with parser.js
4380+     * @constructor
4381+     */
4382+    var FormulaParser = function (handler) {
4383+        var formulaLexer = function () { };
4384+        formulaLexer.prototype = Parser_1.Parser.lexer;
4385+        var formulaParser = function () {
4386+            this.lexer = new formulaLexer();
4387+            this.yy = {};
4388+        };
4389+        formulaParser.prototype = Parser_1.Parser;
4390+        var newParser = new formulaParser;
4391+        newParser.setObj = function (obj) {
4392+            newParser.yy.obj = obj;
4393+        };
4394+        newParser.yy.parseError = function (str, hash) {
4395+            throw {
4396+                name: 'Parser error',
4397+                message: str,
4398+                prop: hash
4399+            };
4400+        };
4401+        newParser.yy.handler = handler;
4402+        return newParser;
4403+    };
4404+    /**
4405+     * Holds cell values, and allows for the updating and manipulation of those cells.
4406+     */
4407+    var Matrix = (function () {
4408+        function Matrix() {
4409+            /**
4410+             * Holds cells inside an object for quick access.
4411+             */
4412+            this.data = {};
4413+        }
4414+        /**
4415+         * Gets the cell corresponding to the key. If the value is not defined, will return undefined.
4416+         * @param key to look up cell
4417+         * @returns {Cell} to return, if it exists. Returns undefined if key not in matrix.
4418+         */
4419+        Matrix.prototype.getCell = function (key) {
4420+            return this.data[key];
4421+        };
4422+        /**
4423+         * Add cell to matrix. If it exists, update the necessary values. If it doesn't exist add it.
4424+         * @param cell to add to matrix.
4425+         * @returns {Cell} Returns the cell after it has been added.
4426+         */
4427+        Matrix.prototype.addCell = function (cell) {
4428+            var cellId = cell.getId();
4429+            if (!(cellId in this.data)) {
4430+                this.data[cellId] = cell;
4431+            }
4432+            else {
4433+                this.getCell(cellId).updateDependencies(cell.getDependencies());
4434+                this.getCell(cellId).setValue(cell.getValue());
4435+                this.getCell(cellId).setError(cell.getError());
4436+            }
4437+            return this.getCell(cellId);
4438+        };
4439+        /**
4440+         * Get all dependencies for a specific cell.
4441+         * @param id of cell
4442+         * @returns {Array} of A1-format cell ID dependencies, in no particular oder.
4443+         */
4444+        Matrix.prototype.getDependencies = function (id) {
4445+            var getDependencies = function (id) {
4446+                var filtered = [];
4447+                for (var key in this.data) {
4448+                    var cell = this.data[key];
4449+                    if (cell.dependencies) {
4450+                        if (cell.dependencies.indexOf(id) > -1) {
4451+                            filtered.push(cell);
4452+                        }
4453+                    }
4454+                }
4455+                var deps = [];
4456+                filtered.forEach(function (cell) {
4457+                    if (deps.indexOf(cell.id) === -1) {
4458+                        deps.push(cell.id);
4459+                    }
4460+                });
4461+                return deps;
4462+            }.bind(this);
4463+            var allDependencies = [];
4464+            var getTotalDependencies = function (id) {
4465+                var deps = getDependencies(id);
4466+                if (deps.length) {
4467+                    deps.forEach(function (refId) {
4468+                        if (allDependencies.indexOf(refId) === -1) {
4469+                            allDependencies.push(refId);
4470+                            var cell = this.getCell(refId);
4471+                            if (cell.getDependencies().length) {
4472+                                getTotalDependencies(refId);
4473+                            }
4474+                        }
4475+                    }.bind(this));
4476+                }
4477+            }.bind(this);
4478+            getTotalDependencies(id);
4479+            return allDependencies;
4480+        };
4481+        /**
4482+         * Set a cell in this matrix. Could update an existing cell, or add a new one.
4483+         * @param id to of cell to create of update
4484+         * @param rawFormula of cell to create or update
4485+         */
4486+        Matrix.prototype.setCell = function (id, rawFormula) {
4487+            var cell = new Cell_1.Cell(id);
4488+            cell.setRawValue(rawFormula);
4489+            registerCellInMatrix(cell);
4490+            recalculateCellDependencies(cell);
4491+        };
4492+        return Matrix;
4493+    }());
4494+    /**
4495+     * Recalculate a cell's dependencies. Involves recalculating cell formulas for ALL dependencies.
4496+     * @param cell to recalculate dependencies
4497+     */
4498+    var recalculateCellDependencies = function (cell) {
4499+        var allDependencies = instance.matrix.getDependencies(cell.getId());
4500+        allDependencies.forEach(function (refId) {
4501+            var currentCell = instance.matrix.getCell(refId);
4502+            if (currentCell && currentCell.hasFormula()) {
4503+                calculateCellFormula(currentCell);
4504+            }
4505+        });
4506+    };
4507+    /**
4508+     * Calculate a cell's formula by parsing it, and updating it's value and error fields.
4509+     * @param cell to calculate
4510+     * @returns {{error: null, result: null}} parsed result
4511+     */
4512+    var calculateCellFormula = function (cell) {
4513+        // to avoid double translate formulas, update cell data in parser
4514+        var parsed = parse(cell.getFormula(), cell.getId());
4515+        instance.matrix.getCell(cell.getId()).setValue(parsed.result);
4516+        instance.matrix.getCell(cell.getId()).setError(parsed.error);
4517+        return parsed;
4518+    };
4519+    /**
4520+     * Register a cell in the matrix, and calculate its formula if it has one.
4521+     * @param cell to register
4522+     */
4523+    var registerCellInMatrix = function (cell) {
4524+        instance.matrix.addCell(cell);
4525+        if (cell.hasFormula()) {
4526+            calculateCellFormula(cell);
4527+        }
4528+    };
4529+    var utils = {
4530+        isArray: function (value) {
4531+            return value instanceof Array;
4532+        },
4533+        isFunction: function (value) {
4534+            return value instanceof Function;
4535+        },
4536+        isNull: function (value) {
4537+            return value === null;
4538+        },
4539+        isSet: function (value) {
4540+            return !utils.isNull(value);
4541+        },
4542+        toNum: function (chr) {
4543+            chr = utils.clearFormula(chr);
4544+            var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
4545+            for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
4546+                result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
4547+            }
4548+            if (result) {
4549+                --result;
4550+            }
4551+            return result;
4552+        },
4553+        toChar: function (num) {
4554+            var s = '';
4555+            while (num >= 0) {
4556+                s = String.fromCharCode(num % 26 + 97) + s;
4557+                num = Math.floor(num / 26) - 1;
4558+            }
4559+            return s.toUpperCase();
4560+        },
4561+        XYtoA1: function (x, y) {
4562+            function numberToLetters(num) {
4563+                var mod = num % 26, pow = num / 26 | 0, out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
4564+                return pow ? numberToLetters(pow) + out : out;
4565+            }
4566+            return numberToLetters(x + 1) + (y + 1).toString();
4567+        },
4568+        cellCoords: function (cell) {
4569+            var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
4570+            return {
4571+                row: parseInt(num[0], 10) - 1,
4572+                col: utils.toNum(alpha)
4573+            };
4574+        },
4575+        clearFormula: function (formula) {
4576+            return formula.replace(/\$/g, '');
4577+        },
4578+        iterateCells: function (startCell, endCell, callback) {
4579+            var result = {
4580+                index: [],
4581+                value: [] // list of cell value
4582+            };
4583+            var cols = {
4584+                start: 0,
4585+                end: 0
4586+            };
4587+            if (endCell.col >= startCell.col) {
4588+                cols = {
4589+                    start: startCell.col,
4590+                    end: endCell.col
4591+                };
4592+            }
4593+            else {
4594+                cols = {
4595+                    start: endCell.col,
4596+                    end: startCell.col
4597+                };
4598+            }
4599+            var rows = {
4600+                start: 0,
4601+                end: 0
4602+            };
4603+            if (endCell.row >= startCell.row) {
4604+                rows = {
4605+                    start: startCell.row,
4606+                    end: endCell.row
4607+                };
4608+            }
4609+            else {
4610+                rows = {
4611+                    start: endCell.row,
4612+                    end: startCell.row
4613+                };
4614+            }
4615+            for (var column = cols.start; column <= cols.end; column++) {
4616+                for (var row = rows.start; row <= rows.end; row++) {
4617+                    var cellIndex = utils.toChar(column) + (row + 1), cellValue = instance.helper.cellValue.call(this, cellIndex);
4618+                    result.index.push(cellIndex);
4619+                    result.value.push(cellValue);
4620+                }
4621+            }
4622+            if (utils.isFunction(callback)) {
4623+                return callback.apply(callback, [result]);
4624+            }
4625+            else {
4626+                return result;
4627+            }
4628+        },
4629+        sort: function (rev) {
4630+            return function (a, b) {
4631+                return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
4632+            };
4633+        }
4634+    };
4635+    var helper = {
4636+        /**
4637+         * Is the value a number or can the value be interpreted as a number
4638+         */
4639+        number: TypeConverter_1.TypeConverter.valueToNumber,
4640+        string: function (str) {
4641+            return str.substring(1, str.length - 1);
4642+        },
4643+        numberInverted: function (num) {
4644+            return this.number(num) * (-1);
4645+        },
4646+        specialMatch: function (type, exp1, exp2) {
4647+            var result;
4648+            switch (type) {
4649+                case '&':
4650+                    result = exp1.toString() + exp2.toString();
4651+                    break;
4652+            }
4653+            return result;
4654+        },
4655+        logicMatch: function (type, exp1, exp2) {
4656+            var result;
4657+            switch (type) {
4658+                case '=':
4659+                    result = (exp1 === exp2);
4660+                    break;
4661+                case '>':
4662+                    result = (exp1 > exp2);
4663+                    break;
4664+                case '<':
4665+                    result = (exp1 < exp2);
4666+                    break;
4667+                case '>=':
4668+                    result = (exp1 >= exp2);
4669+                    break;
4670+                case '<=':
4671+                    result = (exp1 === exp2);
4672+                    break;
4673+                case '<>':
4674+                    result = (exp1 != exp2);
4675+                    break;
4676+                case 'NOT':
4677+                    result = (exp1 != exp2);
4678+                    break;
4679+            }
4680+            return result;
4681+        },
4682+        mathMatch: function (type, number1, number2) {
4683+            var result;
4684+            number1 = helper.number(number1);
4685+            number2 = helper.number(number2);
4686+            switch (type) {
4687+                case '+':
4688+                    result = number1 + number2;
4689+                    break;
4690+                case '-':
4691+                    result = number1 - number2;
4692+                    break;
4693+                case '/':
4694+                    if (number2 === 0) {
4695+                        throw new Errors_1.DivZeroError("Evaluation caused divide by zero error.");
4696+                    }
4697+                    if (number2 !== 0 && number1 === 0) {
4698+                        result = 0;
4699+                    }
4700+                    result = number1 / number2;
4701+                    if (result == Infinity) {
4702+                        throw new Errors_1.DivZeroError("Evaluation caused divide by zero error.");
4703+                    }
4704+                    else if (isNaN(result)) {
4705+                        throw new Errors_1.DivZeroError("Evaluation caused divide by zero error.");
4706+                    }
4707+                    break;
4708+                case '*':
4709+                    result = number1 * number2;
4710+                    break;
4711+                case '^':
4712+                    result = Math.pow(number1, number2);
4713+                    break;
4714+            }
4715+            return result;
4716+        },
4717+        callFunction: function (fn, args) {
4718+            fn = fn.toUpperCase();
4719+            args = args || [];
4720+            if (Formulas_1.Formulas.exists(fn)) {
4721+                return Formulas_1.Formulas.get(fn).apply(this, args);
4722+            }
4723+            throw new Errors_1.NameError("Unknown function: '" + fn + "'.");
4724+        },
4725+        callVariable: function (args) {
4726+            args = args || [];
4727+            var str = args.shift(); // the first in args is the name of the function to call.
4728+            if (str) {
4729+                str = str.toUpperCase();
4730+                if (Formulas_1.Formulas.exists(str)) {
4731+                    return Formulas_1.Formulas.get(str).apply(this, args);
4732+                }
4733+            }
4734+            throw new Errors_1.NameError("Unknown variable: '" + str + "'.");
4735+        },
4736+        cellValue: function (cellId) {
4737+            var value, origin = this, cell = instance.matrix.getCell(cellId);
4738+            // get value, defaulting to undefined
4739+            value = cell ? cell.getValue() : undefined;
4740+            //update dependencies
4741+            instance.matrix.getCell(origin).updateDependencies([cellId]);
4742+            // check references error
4743+            if (cell && cell.getDependencies()) {
4744+                if (cell.getDependencies().indexOf(cellId) !== -1) {
4745+                    throw new Errors_1.RefError("Reference does not exist.");
4746+                }
4747+            }
4748+            // check if any error occurs
4749+            if (cell && cell.getError()) {
4750+                throw cell.getError();
4751+            }
4752+            // return value if is set
4753+            if (utils.isSet(value)) {
4754+                var result = instance.helper.number(value);
4755+                return !isNaN(result) ? result : value;
4756+            }
4757+            // cell is not available
4758+            return undefined;
4759+        },
4760+        cellRangeValue: function (start, end) {
4761+            var coordsStart = utils.cellCoords(start), coordsEnd = utils.cellCoords(end), origin = this;
4762+            // iterate cells to get values and indexes
4763+            var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd), result = [];
4764+            //update dependencies
4765+            instance.matrix.getCell(origin).updateDependencies(cells.index);
4766+            result.push(cells.value);
4767+            return result;
4768+        },
4769+        fixedCellValue: function (id) {
4770+            id = id.replace(/\$/g, '');
4771+            return instance.helper.cellValue.call(this, id);
4772+        },
4773+        fixedCellRangeValue: function (start, end) {
4774+            start = start.replace(/\$/g, '');
4775+            end = end.replace(/\$/g, '');
4776+            return instance.helper.cellRangeValue.call(this, start, end);
4777+        }
4778+    };
4779+    /**
4780+     * Parse a formula for a particular cell. Involves calculating all dependencies and potentially updating them as well.
4781+     * @param formula to parse
4782+     * @param cellId necessary for dependency access
4783+     * @returns {{error: null, result: null}} a parsed value including an error, and potential resulting value
4784+     */
4785+    var parse = function (formula, cellId) {
4786+        var result = null;
4787+        var error = null;
4788+        try {
4789+            parser.setObj(cellId);
4790+            result = parser.parse(formula);
4791+            var deps = instance.matrix.getDependencies(cellId);
4792+            if (deps.indexOf(cellId) !== -1) {
4793+                result = null;
4794+                deps.forEach(function (id) {
4795+                    instance.matrix.getCell(id).setError(new Errors_1.RefError("Reference does not exist"));
4796+                    instance.matrix.getCell(id).clearValue();
4797+                });
4798+                throw new Errors_1.RefError("Reference does not exist.");
4799+            }
4800+        }
4801+        catch (ex) {
4802+            error = ex;
4803+        }
4804+        return {
4805+            error: error,
4806+            result: result
4807+        };
4808+    };
4809+    /**
4810+     * Set a cell value by A1-format cell ID
4811+     * @param id of cel to set
4812+     * @param value raw input to update the cell with
4813+     */
4814+    var setCell = function (id, value) {
4815+        instance.matrix.setCell(id, value.toString());
4816+    };
4817+    /**
4818+     * Get a cell by A1-format cell ID, if it exists in the Sheet. If not return null.
4819+     * @param id to lookup the cell
4820+     * @returns {Cell} cell found, or null.
4821+     */
4822+    var getCell = function (id) {
4823+        var cell = instance.matrix.getCell(id);
4824+        if (cell === undefined) {
4825+            return null;
4826+        }
4827+        return cell;
4828+    };
4829+    /**
4830+     * Load a matrix into this sheet. Matrix values can be of any type, as long as they have a toString()
4831+     * @param input matrix
4832+     */
4833+    this.load = function (input) {
4834+        for (var y = 0; y < input.length; y++) {
4835+            for (var x = 0; x < input[0].length; x++) {
4836+                // set the cell here
4837+                var id = utils.XYtoA1(x, y);
4838+                this.setCell(id, input[y][x].toString());
4839+            }
4840+        }
4841+    };
4842+    /**
4843+     * Render this Sheet as a string in which each row is a cell.
4844+     * @returns {string}
4845+     */
4846+    this.toString = function () {
4847+        var toReturn = "";
4848+        for (var key in this.matrix.data) {
4849+            toReturn += this.matrix.data[key].toString() + "\n";
4850+        }
4851+        return toReturn;
4852+    };
4853+    parser = FormulaParser(instance);
4854+    instance.matrix = new Matrix();
4855+    this.utils = utils;
4856+    this.helper = helper;
4857+    this.parse = parse;
4858+    this.setCell = setCell;
4859+    this.getCell = getCell;
4860+});
4861+exports.Sheet = Sheet;
4862diff --git a/dist/Utilities/ArgsChecker.js b/dist/Utilities/ArgsChecker.js
4863new file mode 100644
4864index 0000000..ff7c368
4865--- /dev/null
4866+++ b/dist/Utilities/ArgsChecker.js
4867@@ -0,0 +1,52 @@
4868+"use strict";
4869+exports.__esModule = true;
4870+var Errors_1 = require("../Errors");
4871+/**
4872+ * Static class to check argument length within expected ranges when calling functions.
4873+ */
4874+var ArgsChecker = (function () {
4875+    function ArgsChecker() {
4876+    }
4877+    /**
4878+     * Checks to see if the arguments are of the correct length.
4879+     * @param args to check length of
4880+     * @param length expected length
4881+     * @param caller name of the function calling this function, for use in error message formatting
4882+     */
4883+    ArgsChecker.checkLength = function (args, length, caller) {
4884+        if (args.length !== length) {
4885+            var functionName = caller !== undefined ? " to " + caller : "";
4886+            throw new Errors_1.NAError("Wrong number of arguments" + functionName + ". Expected " + length
4887+                + " arguments, but got " + args.length + " arguments.");
4888+        }
4889+    };
4890+    /**
4891+     * Checks to see if the arguments are at least a certain length.
4892+     * @param args to check length of
4893+     * @param length expected length
4894+     * @param caller name of the function calling this function, for use in error message formatting
4895+     */
4896+    ArgsChecker.checkAtLeastLength = function (args, length, caller) {
4897+        if (args.length < length) {
4898+            var functionName = caller !== undefined ? " to " + caller : "";
4899+            throw new Errors_1.NAError("Wrong number of arguments" + functionName + ". Expected " + length
4900+                + " arguments, but got " + args.length + " arguments.");
4901+        }
4902+    };
4903+    /**
4904+     * Checks to see if the arguments are within a max and min, inclusively
4905+     * @param args to check length of
4906+     * @param low least number of arguments
4907+     * @param high max number of arguments
4908+     * @param caller name of the function calling this function, for use in error message formatting
4909+     */
4910+    ArgsChecker.checkLengthWithin = function (args, low, high, caller) {
4911+        if (args.length > high || args.length < low) {
4912+            var functionName = caller !== undefined ? " to " + caller : "";
4913+            throw new Errors_1.NAError("Wrong number of arguments" + functionName + ". Expected between " + low
4914+                + " and " + high + " arguments, but got " + args.length + " arguments.");
4915+        }
4916+    };
4917+    return ArgsChecker;
4918+}());
4919+exports.ArgsChecker = ArgsChecker;
4920diff --git a/dist/Utilities/CriteriaFunctionFactory.js b/dist/Utilities/CriteriaFunctionFactory.js
4921new file mode 100644
4922index 0000000..6788961
4923--- /dev/null
4924+++ b/dist/Utilities/CriteriaFunctionFactory.js
4925@@ -0,0 +1,95 @@
4926+"use strict";
4927+exports.__esModule = true;
4928+/**
4929+ * Converts wild-card style expressions (in which * matches zero or more characters, and ? matches exactly one character)
4930+ * to regular expressions. * and ? can be escaped by prefixing with ~.
4931+ * For future reference, something like this might be better
4932+ * http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex.
4933+ * @param c input
4934+ * @returns {RegExp} resulting regex
4935+ */
4936+function wildCardRegex(c) {
4937+    var a = c.split("~?");
4938+    for (var i = 0; i < a.length; i++) {
4939+        a[i] = a[i].split("?").join(".{1}");
4940+    }
4941+    var b = a.join("\\\?");
4942+    var d = b.split("~*");
4943+    for (var i = 0; i < d.length; i++) {
4944+        d[i] = d[i].split("*").join(".*");
4945+    }
4946+    return new RegExp("^" + d.join(".*") + "$", "g");
4947+}
4948+/**
4949+ * Creates a criteria function to evaluate elements in a range in an *IF function.
4950+ */
4951+var CriteriaFunctionFactory = (function () {
4952+    function CriteriaFunctionFactory() {
4953+    }
4954+    /**
4955+     * If the criteria is a number, use strict equality checking.
4956+     * If the criteria is a string, check to see if it is a comparator.
4957+     * If the criteria is a string, and it is not a comparator, check for regex.
4958+     * If the criteria is a string and has not matched the above, finally use strict equality checking as a fallback.
4959+     * If the criteria has not been set, default to false-returning criteria function.
4960+     * @param criteria
4961+     * @returns {(x:any)=>boolean}
4962+     */
4963+    CriteriaFunctionFactory.createCriteriaFunction = function (criteria) {
4964+        // Default criteria does nothing
4965+        var criteriaEvaluation = function (x) {
4966+            return false;
4967+        };
4968+        if (typeof criteria === "number" || typeof criteria === "boolean") {
4969+            criteriaEvaluation = function (x) {
4970+                return x === criteria;
4971+            };
4972+        }
4973+        else if (typeof criteria === "string") {
4974+            var comparisonMatches = criteria.match(/^\s*(<=|>=|=|<>|>|<)\s*(-)?\s*(\$)?\s*([0-9]+([,.][0-9]+)?)\s*$/);
4975+            if (comparisonMatches !== null && comparisonMatches.length >= 6 && comparisonMatches[4] !== undefined) {
4976+                criteriaEvaluation = function (x) {
4977+                    return eval(x + comparisonMatches[1] + (comparisonMatches[2] === undefined ? "" : "-") + comparisonMatches[4]);
4978+                };
4979+                if (comparisonMatches[1] === "=") {
4980+                    criteriaEvaluation = function (x) {
4981+                        return eval(x + "===" + (comparisonMatches[2] === undefined ? "" : "-") + comparisonMatches[4]);
4982+                    };
4983+                }
4984+                if (comparisonMatches[1] === "<>") {
4985+                    criteriaEvaluation = function (x) {
4986+                        return eval(x + "!==" + (comparisonMatches[2] === undefined ? "" : "-") + comparisonMatches[4]);
4987+                    };
4988+                }
4989+            }
4990+            else if (criteria.match(/\*|\~\*|\?|\~\?/) !== null) {
4991+                // Regular string
4992+                var matches = criteria.match(/\*|\~\*|\?|\~\?/);
4993+                if (matches !== null) {
4994+                    criteriaEvaluation = function (x) {
4995+                        try {
4996+                            // http://stackoverflow.com/questions/26246601/wildcard-string-comparison-in-javascript
4997+                            return wildCardRegex(criteria).test(x);
4998+                        }
4999+                        catch (e) {
5000+                            return false;
5001+                        }
5002+                    };
5003+                }
5004+                else {
5005+                    criteriaEvaluation = function (x) {
5006+                        return x === criteria;
5007+                    };
5008+                }
5009+            }
5010+            else {
5011+                criteriaEvaluation = function (x) {
5012+                    return x === criteria;
5013+                };
5014+            }
5015+        }
5016+        return criteriaEvaluation;
5017+    };
5018+    return CriteriaFunctionFactory;
5019+}());
5020+exports.CriteriaFunctionFactory = CriteriaFunctionFactory;
5021diff --git a/dist/Utilities/DateRegExBuilder.js b/dist/Utilities/DateRegExBuilder.js
5022new file mode 100644
5023index 0000000..33f8a2b
5024--- /dev/null
5025+++ b/dist/Utilities/DateRegExBuilder.js
5026@@ -0,0 +1,188 @@
5027+"use strict";
5028+exports.__esModule = true;
5029+/**
5030+ * Build a regular expression step by step, to make it easier to build and read the resulting regular expressions.
5031+ */
5032+var DateRegExBuilder = (function () {
5033+    function DateRegExBuilder() {
5034+        this.regexString = "";
5035+    }
5036+    DateRegExBuilder.DateRegExBuilder = function () {
5037+        return new DateRegExBuilder();
5038+    };
5039+    /**
5040+     * Start the regular expression builder by matching the start of a line and zero or more spaces.
5041+     * @returns {DateRegExBuilder} builder
5042+     */
5043+    DateRegExBuilder.prototype.start = function () {
5044+        this.regexString += "^" + DateRegExBuilder.ZERO_OR_MORE_SPACES;
5045+        return this;
5046+    };
5047+    /**
5048+     * End the regular expression builder by matching the end of the line.
5049+     * @returns {DateRegExBuilder} builder
5050+     */
5051+    DateRegExBuilder.prototype.end = function () {
5052+        this.regexString += "$";
5053+        return this;
5054+    };
5055+    /**
5056+     * Capture all month full name and short names to the regular expression.
5057+     * @returns {DateRegExBuilder} builder
5058+     */
5059+    DateRegExBuilder.prototype.MONTHNAME = function () {
5060+        this.regexString += "(january|february|march|april|may|june|july|august|september|october|november|december|jan|feb|mar|apr|jun|jul|aug|sep|oct|nov|dec)";
5061+        return this;
5062+    };
5063+    /**
5064+     * Capture all month full name and short names to the regular expression, in addition to any followed by one or more
5065+     * spaces.
5066+     * @returns {DateRegExBuilder} builder
5067+     * @constructor
5068+     */
5069+    DateRegExBuilder.prototype.MONTHNAME_W_SPACE = function () {
5070+        this.regexString += "(january|february|march|april|may|june|july|august|september|october|november|december|jan|feb|mar|apr|jun|jul|aug|sep|oct|nov|dec|january\\s+|february\\s+|march\\s+|april\\s+|may\\s+|june\\s+|july\\s+|august\\s+|september\\s+|october\\s+|november\\s+|december\\s+|jan\\s+|feb\\s+|mar\\s+|apr\\s+|jun\\s+|jul\\s+|aug\\s+|sep\\s+|oct\\s+|nov\\s+|dec\\s+)";
5071+        return this;
5072+    };
5073+    /**
5074+     * Add capture group for optionally capturing day names.
5075+     * @returns {DateRegExBuilder} builder
5076+     * @constructor
5077+     */
5078+    DateRegExBuilder.prototype.OPTIONAL_DAYNAME = function () {
5079+        this.regexString += "(sunday|monday|tuesday|wednesday|thursday|friday|saturday|sun|mon|tue|wed|thu|fri|sat)?";
5080+        return this;
5081+    };
5082+    /**
5083+     * Add capture group for optionally capturing a comma followed by one or more spaces.
5084+     * @returns {DateRegExBuilder} builder
5085+     * @constructor
5086+     */
5087+    DateRegExBuilder.prototype.OPTIONAL_COMMA = function () {
5088+        this.regexString += "(,?\\s+)?";
5089+        return this;
5090+    };
5091+    /**
5092+     * Add capture group for capturing month digits between 01 and 12, inclusively.
5093+     * @returns {DateRegExBuilder} builder
5094+     * @constructor
5095+     */
5096+    DateRegExBuilder.prototype.MM = function () {
5097+        this.regexString += "([1-9]|0[1-9]|1[0-2])";
5098+        return this;
5099+    };
5100+    /**
5101+     * Add capture group for capturing month digits between 01 and 12, inclusively, in addition to any followed by one or
5102+     * more spaces.
5103+     * @returns {DateRegExBuilder} builder
5104+     * @constructor
5105+     */
5106+    DateRegExBuilder.prototype.MM_W_SPACE = function () {
5107+        this.regexString += "([1-9]|0[1-9]|1[0-2]|[1-9]\\s+|0[1-9]\\s+|1[0-2]\\s+)";
5108+        return this;
5109+    };
5110+    /**
5111+     * Add capture group for capturing day digits between 01 and 31, inclusively.
5112+     * @returns {DateRegExBuilder} builder
5113+     * @constructor
5114+     */
5115+    DateRegExBuilder.prototype.DD = function () {
5116+        this.regexString += "(0?[0-9]|1[0-9]|2[0-9]|3[0-1])";
5117+        return this;
5118+    };
5119+    /**
5120+     * Add capture group for capturing day digits between 01 and 31, inclusively, in addition to any followed by one or
5121+     * more spaces.
5122+     * @returns {DateRegExBuilder} builder
5123+     * @constructor
5124+     */
5125+    DateRegExBuilder.prototype.DD_W_SPACE = function () {
5126+        this.regexString += "(0?[0-9]|1[0-9]|2[0-9]|3[0-1]|0?[0-9]\\s+|1[0-9]\\s+|2[0-9]\\s+|3[0-1]\\s+)";
5127+        return this;
5128+    };
5129+    /**
5130+     * Add capture group for capturing 4 digits or 3 digits starting with 0-9.
5131+     * @returns {DateRegExBuilder} builder
5132+     * @constructor
5133+     */
5134+    DateRegExBuilder.prototype.YYYY = function () {
5135+        this.regexString += "([0-9]{4}|[1-9][0-9][0-9])";
5136+        return this;
5137+    };
5138+    /**
5139+     * Add capture group for capturing 1 through 4 digits.
5140+     * @returns {DateRegExBuilder} builder
5141+     * @constructor
5142+     */
5143+    DateRegExBuilder.prototype.YYYY14 = function () {
5144+        this.regexString += "([0-9]{1,4})";
5145+        return this;
5146+    };
5147+    /**
5148+     * Add capture group for capturing 1 through 4 digits, in addition to any followed by one or more spaces.
5149+     * @returns {DateRegExBuilder} builder
5150+     * @constructor
5151+     */
5152+    DateRegExBuilder.prototype.YYYY14_W_SPACE = function () {
5153+        this.regexString += "([0-9]{1,4}|[0-9]{1,4}\\s+)";
5154+        return this;
5155+    };
5156+    DateRegExBuilder.prototype.YYYY2_OR_4_W_SPACE = function () {
5157+        this.regexString += "([0-9]{2}|[0-9]{4}|[0-9]{2}\\s+|[0-9]{4}\\s+)";
5158+        return this;
5159+    };
5160+    /**
5161+     * Add capture group for a flexible delimiter, including ", ", " ", ". ", "\", "-".
5162+     * @returns {DateRegExBuilder} builder
5163+     * @constructor
5164+     */
5165+    DateRegExBuilder.prototype.FLEX_DELIMITER = function () {
5166+        // this.regexString += "(,?\\s+|\\s*-?\\.?-?\\/?\\s+)";// close to being right
5167+        this.regexString += "(,?\\s+|\\s*\\.\\s+|\\s*-\\s*|\\s*\\/\\s*)";
5168+        return this;
5169+    };
5170+    /**
5171+     * Add capture group for a flexible delimiter, including ", ", " ", ".", "\", "-". Different from FLEX_DELIMITER
5172+     * in that it will match periods with zero or more spaces on either side.
5173+     * For reference: https://regex101.com/r/q1fp1z/1/
5174+     * @returns {DateRegExBuilder} builder
5175+     * @constructor
5176+     */
5177+    DateRegExBuilder.prototype.FLEX_DELIMITER_LOOSEDOT = function () {
5178+        // this.regexString += "(,?\\s+|\\s*-?\\.?-?\\/?\\s+)";// close to being right
5179+        this.regexString += "(,?\\s+|\\s*\\.\\s*|\\s*-\\s*|\\s*\\/\\s*)";
5180+        return this;
5181+    };
5182+    /**
5183+     * Add an optional capture group for capturing timestamps including: "10am", "10:10", "10:10pm", "10:10:10",
5184+     * "10:10:10am", along with zero or more spaces after semi colons, AM or PM, and unlimited number of digits per unit.
5185+     * @returns {DateRegExBuilder} builder
5186+     * @constructor
5187+     */
5188+    DateRegExBuilder.prototype.OPTIONAL_TIMESTAMP_CAPTURE_GROUP = function () {
5189+        this.regexString += "((\\s+[0-9]+\\s*am\\s*$|[0-9]+\\s*pm\\s*$)|(\\s+[0-9]+:\\s*[0-9]+\\s*$)|(\\s+[0-9]+:\\s*[0-9]+\\s*am\\s*$|\\s+[0-9]+:\\s*[0-9]+\\s*pm\\s*$)|(\\s+[0-9]+:\\s*[0-9]+:\\s*[0-9]+\\s*$)|(\\s+[0-9]+:\\s*[0-9]+:\\s*[0-9]+\\s*am\\s*$|[0-9]+:\\s*[0-9]+:\\s*[0-9]+\\s*pm\\s*$))?";
5190+        return this;
5191+    };
5192+    /**
5193+     * Add a capture group for capturing timestamps including: "10am", "10:10", "10:10pm", "10:10:10",
5194+     * "10:10:10am", along with zero or more spaces after semi colons, AM or PM, and unlimited number of digits per unit.
5195+     * See https://regex101.com/r/0bmj5n/1/ for more information of 9-digit maximum. One series, "12:00001989198298am",
5196+     * has a maximum of 10 digits: "0*(?:[1-9]{1}[0-9]{0,9})?"
5197+     * @returns {DateRegExBuilder} builder
5198+     * @constructor
5199+     */
5200+    DateRegExBuilder.prototype.TIMESTAMP_UNITS_CAPTURE_GROUP = function () {
5201+        this.regexString += "(\\s*(0*(?:[1-9]{1}[0-9]{0,8})?)()()\\s*(am|pm)\\s*$)|(\\s*(0*(?:[1-9]{1}[0-9]{0,8})?):\\s*(0*(?:[1-9]{1}[0-9]{0,8})?)()()\\s*$)|(\\s*((0*(?:[1-9]{1}[0-9]{0,8})?):\\s*(0*(?:[1-9]{1}[0-9]{0,9})?)()\\s*(am|pm))\\s*$)|(\\s*((0*(?:[1-9]{1}[0-9]{0,8})?):\\s*(0*(?:[1-9]{1}[0-9]{0,8})?):\\s*(0*(?:[1-9]{1}[0-9]{0,8})?)())\\s*$)|(\\s*((0*(?:[1-9]{1}[0-9]{0,8})?):\\s*(0*(?:[1-9]{1}[0-9]{0,8})?):\\s*(0*(?:[1-9]{1}[0-9]{0,8})?)\\s*(am|pm))\\s*$)";
5202+        return this;
5203+    };
5204+    /**
5205+     * Build the regular expression and ignore case.
5206+     * @returns {RegExp}
5207+     */
5208+    DateRegExBuilder.prototype.build = function () {
5209+        return new RegExp(this.regexString, 'i');
5210+    };
5211+    return DateRegExBuilder;
5212+}());
5213+DateRegExBuilder.ZERO_OR_MORE_SPACES = "\\s*";
5214+exports.DateRegExBuilder = DateRegExBuilder;
5215diff --git a/dist/Utilities/Filter.js b/dist/Utilities/Filter.js
5216new file mode 100644
5217index 0000000..43f553f
5218--- /dev/null
5219+++ b/dist/Utilities/Filter.js
5220@@ -0,0 +1,80 @@
5221+"use strict";
5222+exports.__esModule = true;
5223+var Errors_1 = require("../Errors");
5224+/**
5225+ * Static class to help filter down Arrays
5226+ */
5227+var Filter = (function () {
5228+    function Filter() {
5229+    }
5230+    /**
5231+     * Converts string values in array to 0
5232+     * @param arr to convert
5233+     * @returns {Array} array in which all string values have been converted to 0.
5234+     */
5235+    Filter.stringValuesToZeros = function (arr) {
5236+        var toReturn = [];
5237+        for (var i = 0; i < arr.length; i++) {
5238+            if (typeof arr[i] === "string") {
5239+                toReturn.push(0);
5240+            }
5241+            else {
5242+                toReturn.push(arr[i]);
5243+            }
5244+        }
5245+        return toReturn;
5246+    };
5247+    /**
5248+     * Flatten an array of arrays of ...etc.
5249+     * @param values array of values
5250+     * @returns {Array} flattened array
5251+     */
5252+    Filter.flatten = function (values) {
5253+        return values.reduce(function (flat, toFlatten) {
5254+            return flat.concat(Array.isArray(toFlatten) ? Filter.flatten(toFlatten) : toFlatten);
5255+        }, []);
5256+    };
5257+    /**
5258+     * Flatten an array of arrays of... etc, but throw an error if any are empty references.
5259+     * @param values array of values
5260+     * @returns {Array} flattened array
5261+     */
5262+    Filter.flattenAndThrow = function (values) {
5263+        return values.reduce(function (flat, toFlatten) {
5264+            if (Array.isArray(toFlatten) && toFlatten.length === 0) {
5265+                throw new Errors_1.RefError("Reference does not exist.");
5266+            }
5267+            return flat.concat(Array.isArray(toFlatten) ? Filter.flattenAndThrow(toFlatten) : toFlatten);
5268+        }, []);
5269+    };
5270+    /**
5271+     * Filter out all strings from an array.
5272+     * @param arr to filter
5273+     * @returns {Array} filtered array
5274+     */
5275+    Filter.filterOutStringValues = function (arr) {
5276+        var toReturn = [];
5277+        for (var i = 0; i < arr.length; i++) {
5278+            if (typeof arr[i] !== "string") {
5279+                toReturn.push(arr[i]);
5280+            }
5281+        }
5282+        return toReturn;
5283+    };
5284+    /**
5285+     * Filters out non number values.
5286+     * @param arr to filter
5287+     * @returns {Array} filtered array
5288+     */
5289+    Filter.filterOutNonNumberValues = function (arr) {
5290+        var toReturn = [];
5291+        for (var i = 0; i < arr.length; i++) {
5292+            if (typeof arr[i] !== "string" && typeof arr[i] !== "boolean") {
5293+                toReturn.push(arr[i]);
5294+            }
5295+        }
5296+        return toReturn;
5297+    };
5298+    return Filter;
5299+}());
5300+exports.Filter = Filter;
5301diff --git a/dist/Utilities/MathHelpers.js b/dist/Utilities/MathHelpers.js
5302new file mode 100644
5303index 0000000..a217655
5304--- /dev/null
5305+++ b/dist/Utilities/MathHelpers.js
5306@@ -0,0 +1,359 @@
5307+"use strict";
5308+exports.__esModule = true;
5309+var Errors_1 = require("../Errors");
5310+/**
5311+ * Returns the continued fraction for the incomplete Beta function with parameters a and b modified by Lentz's method
5312+ * evaluated at x. For more information see http://jstat.github.io/special-functions.html#betacf
5313+ */
5314+function betacf(x, a, b) {
5315+    var fpmin = 1e-30;
5316+    var m = 1;
5317+    var qab = a + b;
5318+    var qap = a + 1;
5319+    var qam = a - 1;
5320+    var c = 1;
5321+    var d = 1 - qab * x / qap;
5322+    var m2, aa, del, h;
5323+    // These q's will be used in factors that occur in the coefficients
5324+    if (Math.abs(d) < fpmin)
5325+        d = fpmin;
5326+    d = 1 / d;
5327+    h = d;
5328+    for (; m <= 100; m++) {
5329+        m2 = 2 * m;
5330+        aa = m * (b - m) * x / ((qam + m2) * (a + m2));
5331+        // One step (the even one) of the recurrence
5332+        d = 1 + aa * d;
5333+        if (Math.abs(d) < fpmin)
5334+            d = fpmin;
5335+        c = 1 + aa / c;
5336+        if (Math.abs(c) < fpmin)
5337+            c = fpmin;
5338+        d = 1 / d;
5339+        h *= d * c;
5340+        aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
5341+        // Next step of the recurrence (the odd one)
5342+        d = 1 + aa * d;
5343+        if (Math.abs(d) < fpmin)
5344+            d = fpmin;
5345+        c = 1 + aa / c;
5346+        if (Math.abs(c) < fpmin)
5347+            c = fpmin;
5348+        d = 1 / d;
5349+        del = d * c;
5350+        h *= del;
5351+        if (Math.abs(del - 1.0) < 3e-7)
5352+            break;
5353+    }
5354+    return h;
5355+}
5356+exports.betacf = betacf;
5357+/**
5358+ * Returns the incomplete Beta function evaluated at (x,a,b). See http://jstat.github.io/special-functions.html#ibeta
5359+ * for more information.
5360+ */
5361+function ibeta(x, a, b) {
5362+    // Factors in front of the continued fraction.
5363+    var bt = (x === 0 || x === 1) ? 0 :
5364+        Math.exp(gammaln(a + b) - gammaln(a) -
5365+            gammaln(b) + a * Math.log(x) + b *
5366+            Math.log(1 - x));
5367+    if (x < 0 || x > 1)
5368+        // WARNING: I changed this to 0, because TS complains about doing numerical operations on boolean values.
5369+        // Still safe in javascript, but not TS.
5370+        return 0;
5371+    if (x < (a + 1) / (a + b + 2))
5372+        // Use continued fraction directly.
5373+        return bt * betacf(x, a, b) / a;
5374+    // else use continued fraction after making the symmetry transformation.
5375+    return 1 - bt * betacf(1 - x, b, a) / b;
5376+}
5377+exports.ibeta = ibeta;
5378+/**
5379+ * Returns the inverse of the incomplete Beta function evaluated at (p,a,b). For more information see
5380+ * http://jstat.github.io/special-functions.html#ibetainv
5381+ */
5382+function ibetainv(p, a, b) {
5383+    var EPS = 1e-8;
5384+    var a1 = a - 1;
5385+    var b1 = b - 1;
5386+    var j = 0;
5387+    var lna, lnb, pp, t, u, err, x, al, h, w, afac;
5388+    if (p <= 0)
5389+        return 0;
5390+    if (p >= 1)
5391+        return 1;
5392+    if (a >= 1 && b >= 1) {
5393+        pp = (p < 0.5) ? p : 1 - p;
5394+        t = Math.sqrt(-2 * Math.log(pp));
5395+        x = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;
5396+        if (p < 0.5)
5397+            x = -x;
5398+        al = (x * x - 3) / 6;
5399+        h = 2 / (1 / (2 * a - 1) + 1 / (2 * b - 1));
5400+        w = (x * Math.sqrt(al + h) / h) - (1 / (2 * b - 1) - 1 / (2 * a - 1)) *
5401+            (al + 5 / 6 - 2 / (3 * h));
5402+        x = a / (a + b * Math.exp(2 * w));
5403+    }
5404+    else {
5405+        lna = Math.log(a / (a + b));
5406+        lnb = Math.log(b / (a + b));
5407+        t = Math.exp(a * lna) / a;
5408+        u = Math.exp(b * lnb) / b;
5409+        w = t + u;
5410+        if (p < t / w)
5411+            x = Math.pow(a * w * p, 1 / a);
5412+        else
5413+            x = 1 - Math.pow(b * w * (1 - p), 1 / b);
5414+    }
5415+    afac = -gammaln(a) - gammaln(b) + gammaln(a + b);
5416+    for (; j < 10; j++) {
5417+        if (x === 0 || x === 1)
5418+            return x;
5419+        err = ibeta(x, a, b) - p;
5420+        t = Math.exp(a1 * Math.log(x) + b1 * Math.log(1 - x) + afac);
5421+        u = err / t;
5422+        x -= (t = u / (1 - 0.5 * Math.min(1, u * (a1 / x - b1 / (1 - x)))));
5423+        if (x <= 0)
5424+            x = 0.5 * (x + t);
5425+        if (x >= 1)
5426+            x = 0.5 * (x + t + 1);
5427+        if (Math.abs(t) < EPS * x && j > 0)
5428+            break;
5429+    }
5430+    return x;
5431+}
5432+exports.ibetainv = ibetainv;
5433+/**
5434+ * http://jstat.github.io/distributions.html
5435+ */
5436+function inv(x, df1, df2) {
5437+    return df2 / (df1 * (1 / ibetainv(x, df1 / 2, df2 / 2) - 1));
5438+}
5439+exports.inv = inv;
5440+/**
5441+ * Return the standard deviation of a vector. By defaut, the population standard deviation is returned. Passing true
5442+ * for the flag parameter returns the sample standard deviation. See http://jstat.github.io/vector.html#stdev for
5443+ * more information.
5444+ */
5445+function stdev(arr, flag) {
5446+    return Math.sqrt(variance(arr, flag));
5447+}
5448+exports.stdev = stdev;
5449+/**
5450+ * Return the variance of a vector. By default, the population variance is calculated. Passing true as the flag
5451+ * indicates computes the sample variance instead. See http://jstat.github.io/vector.html#variance for more
5452+ * information.
5453+ */
5454+function variance(arr, flag) {
5455+    if ((arr.length - (flag ? 1 : 0)) === 0) {
5456+        throw new Errors_1.DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
5457+    }
5458+    return sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
5459+}
5460+exports.variance = variance;
5461+/**
5462+ * Return the sum of a vector. See http://jstat.github.io/vector.html#sum for more information.
5463+ */
5464+function sum(arr) {
5465+    var sum = 0;
5466+    var i = arr.length;
5467+    while (--i >= 0) {
5468+        sum += arr[i];
5469+    }
5470+    return sum;
5471+}
5472+exports.sum = sum;
5473+/**
5474+ * Return the mean of a vector. See http://jstat.github.io/vector.html#mean for more information.
5475+ */
5476+function mean(arr) {
5477+    if (arr.length === 0) {
5478+        throw new Errors_1.DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
5479+    }
5480+    return sum(arr) / arr.length;
5481+}
5482+exports.mean = mean;
5483+/**
5484+ * Return the sum of squared errors of prediction of a vector. See http://jstat.github.io/vector.html#sumsqerr for
5485+ * more information.
5486+ */
5487+function sumsqerr(arr) {
5488+    var m = mean(arr);
5489+    var sum = 0;
5490+    var i = arr.length;
5491+    var tmp;
5492+    while (--i >= 0) {
5493+        tmp = arr[i] - m;
5494+        sum += tmp * tmp;
5495+    }
5496+    return sum;
5497+}
5498+exports.sumsqerr = sumsqerr;
5499+/**
5500+ * Return the covariance of two vectors. See http://jstat.github.io/vector.html#covariance for more information.
5501+ */
5502+function covariance(arr1, arr2) {
5503+    var u = mean(arr1);
5504+    var v = mean(arr2);
5505+    var arr1Len = arr1.length;
5506+    var sq_dev = new Array(arr1Len);
5507+    for (var i = 0; i < arr1Len; i++) {
5508+        sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
5509+    }
5510+    if ((arr1Len - 1) === 0) {
5511+        throw new Errors_1.DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
5512+    }
5513+    return sum(sq_dev) / (arr1Len - 1);
5514+}
5515+exports.covariance = covariance;
5516+/**
5517+ * Returns the Log-Gamma function evaluated at x. See http://jstat.github.io/special-functions.html#gammaln for more
5518+ * information.
5519+ */
5520+function gammaln(x) {
5521+    var j = 0;
5522+    var cof = [
5523+        76.18009172947146, -86.50532032941677, 24.01409824083091,
5524+        -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5
5525+    ];
5526+    var ser = 1.000000000190015;
5527+    var xx, y, tmp;
5528+    tmp = (y = xx = x) + 5.5;
5529+    tmp -= (xx + 0.5) * Math.log(tmp);
5530+    for (; j < 6; j++)
5531+        ser += cof[j] / ++y;
5532+    return Math.log(2.5066282746310005 * ser / xx) - tmp;
5533+}
5534+exports.gammaln = gammaln;
5535+/**
5536+ * Returns the Gamma function evaluated at x. This is sometimes called the 'complete' gamma function. See
5537+ * http://jstat.github.io/special-functions.html#gammafn for more information.
5538+ */
5539+function gammafn(x) {
5540+    var p = [-1.716185138865495, 24.76565080557592, -379.80425647094563,
5541+        629.3311553128184, 866.9662027904133, -31451.272968848367,
5542+        -36144.413418691176, 66456.14382024054
5543+    ];
5544+    var q = [-30.8402300119739, 315.35062697960416, -1015.1563674902192,
5545+        -3107.771671572311, 22538.118420980151, 4755.8462775278811,
5546+        -134659.9598649693, -115132.2596755535];
5547+    var fact;
5548+    var n = 0;
5549+    var xden = 0;
5550+    var xnum = 0;
5551+    var y = x;
5552+    var i, z, yi, res;
5553+    if (y <= 0) {
5554+        res = y % 1 + 3.6e-16;
5555+        if (res) {
5556+            fact = (!(y & 1) ? 1 : -1) * Math.PI / Math.sin(Math.PI * res);
5557+            y = 1 - y;
5558+        }
5559+        else {
5560+            return Infinity;
5561+        }
5562+    }
5563+    yi = y;
5564+    if (y < 1) {
5565+        z = y++;
5566+    }
5567+    else {
5568+        z = (y -= n = (y | 0) - 1) - 1;
5569+    }
5570+    for (i = 0; i < 8; ++i) {
5571+        xnum = (xnum + p[i]) * z;
5572+        xden = xden * z + q[i];
5573+    }
5574+    res = xnum / xden + 1;
5575+    if (yi < y) {
5576+        res /= yi;
5577+    }
5578+    else if (yi > y) {
5579+        for (i = 0; i < n; ++i) {
5580+            res *= y;
5581+            y++;
5582+        }
5583+    }
5584+    if (fact) {
5585+        res = fact / res;
5586+    }
5587+    return res;
5588+}
5589+exports.gammafn = gammafn;
5590+/**
5591+ * Returns the value of x in the cdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice
5592+ * that if using the alpha beta convention, scale = 1/beta. For more information see
5593+ * http://jstat.github.io/distributions.html#jStat.gamma.cdf
5594+ */
5595+function cdf(x, df1, df2) {
5596+    return ibeta((df1 * x) / (df1 * x + df2), df1 / 2, df2 / 2);
5597+}
5598+exports.cdf = cdf;
5599+/**
5600+ * Returns the error function evaluated at x. See also:
5601+ *
5602+ * * http://jstat.github.io/special-functions.html#erf
5603+ *
5604+ * * https://github.com/jstat/jstat/search?utf8=%E2%9C%93&q=erf&type=
5605+ *
5606+ * @param x to evaluate
5607+ * @returns {number} error
5608+ */
5609+function erf(x) {
5610+    var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,
5611+        -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,
5612+        4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,
5613+        1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
5614+        6.529054439e-9, 5.059343495e-9, -9.91364156e-10,
5615+        -2.27365122e-10, 9.6467911e-11, 2.394038e-12,
5616+        -6.886027e-12, 8.94487e-13, 3.13092e-13,
5617+        -1.12708e-13, 3.81e-16, 7.106e-15,
5618+        -1.523e-15, -9.4e-17, 1.21e-16,
5619+        -2.8e-17];
5620+    var j = cof.length - 1;
5621+    var isneg = false;
5622+    var d = 0;
5623+    var dd = 0;
5624+    var t, ty, tmp, res;
5625+    if (x < 0) {
5626+        x = -x;
5627+        isneg = true;
5628+    }
5629+    t = 2 / (2 + x);
5630+    ty = 4 * t - 2;
5631+    for (; j > 0; j--) {
5632+        tmp = d;
5633+        d = ty * d - dd + cof[j];
5634+        dd = tmp;
5635+    }
5636+    res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);
5637+    return isneg ? res - 1 : 1 - res;
5638+}
5639+exports.erf = erf;
5640+/**
5641+ * Returns the value of x in the pdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice
5642+ * that if using the alpha beta convention, scale = 1/beta. For more information see
5643+ * http://jstat.github.io/distributions.html#jStat.gamma.pdf
5644+ */
5645+function pdf(x, df1, df2) {
5646+    if (x < 0) {
5647+        return undefined;
5648+    }
5649+    return Math.sqrt((Math.pow(df1 * x, df1) * Math.pow(df2, df2)) /
5650+        (Math.pow(df1 * x + df2, df1 + df2))) /
5651+        (x * betafn(df1 / 2, df2 / 2));
5652+}
5653+exports.pdf = pdf;
5654+function betaln(x, y) {
5655+    return gammaln(x) + gammaln(y) - gammaln(x + y);
5656+}
5657+exports.betaln = betaln;
5658+function betafn(x, y) {
5659+    // ensure arguments are positive
5660+    if (x <= 0 || y <= 0)
5661+        return undefined;
5662+    // make sure x + y doesn't exceed the upper limit of usable values
5663+    return (x + y > 170) ? Math.exp(betaln(x, y)) : gammafn(x) * gammafn(y) / gammafn(x + y);
5664+}
5665+exports.betafn = betafn;
5666diff --git a/dist/Utilities/Serializer.js b/dist/Utilities/Serializer.js
5667new file mode 100644
5668index 0000000..1e94aa9
5669--- /dev/null
5670+++ b/dist/Utilities/Serializer.js
5671@@ -0,0 +1,15 @@
5672+"use strict";
5673+exports.__esModule = true;
5674+/**
5675+ * Class to hold static methods for serialization.
5676+ */
5677+var Serializer = (function () {
5678+    function Serializer() {
5679+    }
5680+    Serializer.serialize = function (value) {
5681+        var t = typeof value;
5682+        return "<" + t + ": " + value + ">";
5683+    };
5684+    return Serializer;
5685+}());
5686+exports.Serializer = Serializer;
5687diff --git a/dist/Utilities/TypeConverter.js b/dist/Utilities/TypeConverter.js
5688new file mode 100644
5689index 0000000..66f7418
5690--- /dev/null
5691+++ b/dist/Utilities/TypeConverter.js
5692@@ -0,0 +1,691 @@
5693+"use strict";
5694+exports.__esModule = true;
5695+/// <reference path="../../node_modules/moment/moment.d.ts"/>
5696+var moment = require("moment");
5697+var Errors_1 = require("../Errors");
5698+var DateRegExBuilder_1 = require("./DateRegExBuilder");
5699+var YEAR_MONTHDIG_DAY = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5700+    .start()
5701+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().YYYY().FLEX_DELIMITER_LOOSEDOT().MM().FLEX_DELIMITER_LOOSEDOT().DD_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5702+    .end()
5703+    .build();
5704+var MONTHDIG_DAY_YEAR = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5705+    .start()
5706+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MM().FLEX_DELIMITER_LOOSEDOT().DD().FLEX_DELIMITER_LOOSEDOT().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5707+    .end()
5708+    .build();
5709+var DAY_MONTHNAME_YEAR = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5710+    .start()
5711+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().DD().FLEX_DELIMITER_LOOSEDOT().MONTHNAME().FLEX_DELIMITER_LOOSEDOT().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5712+    .end()
5713+    .build();
5714+var MONTHNAME_DAY_YEAR = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5715+    .start()
5716+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MONTHNAME().FLEX_DELIMITER_LOOSEDOT().DD().FLEX_DELIMITER_LOOSEDOT().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5717+    .end()
5718+    .build();
5719+var YEAR_MONTHDIG = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5720+    .start()
5721+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().YYYY14().FLEX_DELIMITER().MM_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5722+    .end()
5723+    .build();
5724+var MONTHDIG_YEAR = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5725+    .start()
5726+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MM().FLEX_DELIMITER().YYYY14_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5727+    .end()
5728+    .build();
5729+var YEAR_MONTHNAME = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5730+    .start()
5731+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().YYYY14().FLEX_DELIMITER().MONTHNAME_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5732+    .end()
5733+    .build();
5734+var MONTHNAME_YEAR = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5735+    .start()
5736+    .OPTIONAL_DAYNAME().OPTIONAL_COMMA().MONTHNAME().FLEX_DELIMITER().YYYY2_OR_4_W_SPACE().OPTIONAL_TIMESTAMP_CAPTURE_GROUP()
5737+    .end()
5738+    .build();
5739+// For reference: https://regex101.com/r/47GARA/1/
5740+var TIMESTAMP = DateRegExBuilder_1.DateRegExBuilder.DateRegExBuilder()
5741+    .start()
5742+    .TIMESTAMP_UNITS_CAPTURE_GROUP()
5743+    .end()
5744+    .build();
5745+// The first year to use when calculating the number of days in a date
5746+var FIRST_YEAR = 1900;
5747+// The year 2000.
5748+var Y2K_YEAR = 2000;
5749+/**
5750+ * Matches a timestamp string, adding the units to the moment passed in.
5751+ * @param timestampString to parse. ok formats: "10am", "10:10", "10:10am", "10:10:10", "10:10:10am", etc.
5752+ * @param momentToMutate to mutate
5753+ * @returns {Moment} mutated and altered.
5754+ */
5755+function matchTimestampAndMutateMoment(timestampString, momentToMutate) {
5756+    var matches = timestampString.match(TIMESTAMP);
5757+    if (matches && matches[1] !== undefined) {
5758+        var hours = parseInt(matches[2]);
5759+        if (hours > 12) {
5760+            throw new Error();
5761+        }
5762+        momentToMutate.add(hours, 'hours');
5763+    }
5764+    else if (matches && matches[6] !== undefined) {
5765+        var hours = parseInt(matches[7]);
5766+        var minutes = parseInt(matches[8]);
5767+        momentToMutate.add(hours, 'hours').add(minutes, 'minutes');
5768+    }
5769+    else if (matches && matches[11] !== undefined) {
5770+        var hours = parseInt(matches[13]);
5771+        var minutes = parseInt(matches[14]);
5772+        var pmTrue = (matches[16].toLowerCase() === "pm");
5773+        if (hours > 12) {
5774+            throw new Error();
5775+        }
5776+        if (pmTrue) {
5777+            // 12pm is just 0am, 4pm is 16, etc.
5778+            momentToMutate.set('hours', hours === 12 ? hours : 12 + hours);
5779+        }
5780+        else {
5781+            if (hours !== 12) {
5782+                momentToMutate.set('hours', hours);
5783+            }
5784+        }
5785+        momentToMutate.add(minutes, 'minutes');
5786+    }
5787+    else if (matches && matches[17] !== undefined) {
5788+        var hours = parseInt(matches[19]);
5789+        var minutes = parseInt(matches[20]);
5790+        var seconds = parseInt(matches[21]);
5791+        momentToMutate.add(hours, 'hours').add(minutes, 'minutes').add(seconds, 'seconds');
5792+    }
5793+    else if (matches && matches[23] !== undefined) {
5794+        var hours = parseInt(matches[25]);
5795+        var minutes = parseInt(matches[26]);
5796+        var seconds = parseInt(matches[27]);
5797+        var pmTrue = (matches[28].toLowerCase() === "pm");
5798+        if (hours > 12) {
5799+            throw new Error();
5800+        }
5801+        if (pmTrue) {
5802+            // 12pm is just 0am, 4pm is 16, etc.
5803+            momentToMutate.set('hours', hours === 12 ? hours : 12 + hours);
5804+        }
5805+        else {
5806+            if (hours !== 12) {
5807+                momentToMutate.set('hours', hours);
5808+            }
5809+        }
5810+        momentToMutate.add(minutes, 'minutes').add(seconds, 'seconds');
5811+    }
5812+    else {
5813+        throw new Error();
5814+    }
5815+    return momentToMutate;
5816+}
5817+/**
5818+ * Static class of helpers used to convert various types to each other.
5819+ */
5820+var TypeConverter = (function () {
5821+    function TypeConverter() {
5822+    }
5823+    /**
5824+     * Converts a time-formatted string to a number between 0 and 1, exclusive on 1.
5825+     * @param timeString
5826+     * @returns {number} representing time of day
5827+     */
5828+    TypeConverter.stringToTimeNumber = function (timeString) {
5829+        var m;
5830+        try {
5831+            m = matchTimestampAndMutateMoment(timeString, moment.utc([FIRST_YEAR]).startOf("year"));
5832+        }
5833+        catch (e) {
5834+            m = TypeConverter.parseStringToMoment(timeString);
5835+            if (m === undefined || !m.isValid()) {
5836+                throw new Error();
5837+            }
5838+        }
5839+        // If the parsing didn't work, try parsing as timestring alone
5840+        return (3600 * m.hours() + 60 * m.minutes() + m.seconds()) / 86400;
5841+    };
5842+    /**
5843+     * Parses a string returning a moment that is either valid, invalid or undefined.
5844+     * @param dateString to parse.
5845+     * @returns {moment}
5846+     */
5847+    TypeConverter.parseStringToMoment = function (dateString) {
5848+        var m;
5849+        /**
5850+         * Creates moment object from years, months and days.
5851+         * @param years of moment
5852+         * @param months of moment in number or string format (eg: January)
5853+         * @param days of moment
5854+         * @returns {Moment} created moment
5855+         */
5856+        function createMoment(years, months, days) {
5857+            var actualYear = years;
5858+            if (years >= 0 && years < 30) {
5859+                actualYear = Y2K_YEAR + years;
5860+            }
5861+            else if (years >= 30 && years < 100) {
5862+                actualYear = FIRST_YEAR + years;
5863+            }
5864+            var tmpMoment = moment.utc([actualYear]).startOf("year");
5865+            if (typeof months === "string") {
5866+                tmpMoment.month(months);
5867+            }
5868+            else {
5869+                tmpMoment.set("months", months);
5870+            }
5871+            // If we're specifying more days than there are in this month
5872+            if (days > tmpMoment.daysInMonth() - 1) {
5873+                throw new Error();
5874+            }
5875+            return tmpMoment.add(days, 'days');
5876+        }
5877+        // Check YEAR_MONTHDIG, YYYY(fd)MM, '1992/06'
5878+        // NOTE: Must come before YEAR_MONTHDIG_DAY matching.
5879+        if (m === undefined) {
5880+            var matches = dateString.match(YEAR_MONTHDIG);
5881+            if (matches && matches.length >= 6) {
5882+                var years = parseInt(matches[3]);
5883+                var months = parseInt(matches[5]) - 1; // Months are zero indexed.
5884+                var tmpMoment = createMoment(years, months, 0);
5885+                if (matches[6] !== undefined) {
5886+                    tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
5887+                }
5888+                m = tmpMoment;
5889+            }
5890+        }
5891+        // Check YEAR_MONTHDIG_DAY, YYYY(fd)MM(fd)DD, "1992/06/24"
5892+        if (m === undefined) {
5893+            var matches = dateString.match(YEAR_MONTHDIG_DAY);
5894+            if (matches && matches.length >= 8) {
5895+                // Check delimiters. If they're not the same, throw error.
5896+                if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
5897+                    throw new Error();
5898+                }
5899+                var years = parseInt(matches[3]);
5900+                var months = parseInt(matches[5]) - 1; // Months are zero indexed.
5901+                var days = parseInt(matches[7]) - 1; // Days are zero indexed.
5902+                var tmpMoment = createMoment(years, months, days);
5903+                if (matches.length >= 9 && matches[8] !== undefined) {
5904+                    tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
5905+                }
5906+                m = tmpMoment;
5907+            }
5908+        }
5909+        // Check MONTHDIG_YEAR, MM(fd)YYYY, '06/1992'
5910+        // NOTE: Must come before MONTHDIG_DAY_YEAR matching.
5911+        if (m === undefined) {
5912+            var matches = dateString.match(MONTHDIG_YEAR);
5913+            if (matches && matches.length >= 6) {
5914+                var years = parseInt(matches[5]);
5915+                var months = parseInt(matches[3]) - 1; // Months are zero indexed.
5916+                var tmpMoment = createMoment(years, months, 0);
5917+                if (matches[6] !== undefined) {
5918+                    tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
5919+                }
5920+                m = tmpMoment;
5921+            }
5922+        }
5923+        // Check MONTHDIG_DAY_YEAR, MM(fd)DD(fd)YYYY, "06/24/1992"
5924+        if (m === undefined) {
5925+            var matches = dateString.match(MONTHDIG_DAY_YEAR);
5926+            if (matches && matches.length >= 8) {
5927+                // Check delimiters. If they're not the same, throw error.
5928+                if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
5929+                    throw new Error();
5930+                }
5931+                var years = parseInt(matches[7]);
5932+                var months = parseInt(matches[3]) - 1; // Months are zero indexed.
5933+                var days = parseInt(matches[5]) - 1; // Days are zero indexed.
5934+                var tmpMoment = createMoment(years, months, days);
5935+                if (matches.length >= 9 && matches[8] !== undefined) {
5936+                    tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
5937+                }
5938+                m = tmpMoment;
5939+            }
5940+        }
5941+        // Check MONTHNAME_YEAR, Month(fd)YYYY, 'Aug 1992'
5942+        // NOTE: Needs to come before DAY_MONTHNAME_YEAR matching.
5943+        if (m === undefined) {
5944+            var matches = dateString.match(MONTHNAME_YEAR);
5945+            if (matches && matches.length >= 6) {
5946+                var years = parseInt(matches[5]);
5947+                var monthName = matches[3];
5948+                var tmpMoment = createMoment(years, monthName, 0);
5949+                if (matches[6] !== undefined) {
5950+                    tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
5951+                }
5952+                m = tmpMoment;
5953+            }
5954+        }
5955+        // Check MONTHNAME_DAY_YEAR, Month(fd)DD(fd)YYYY, 'Aug 19 2020'
5956+        if (m === undefined) {
5957+            var matches = dateString.match(MONTHNAME_DAY_YEAR);
5958+            if (matches && matches.length >= 8) {
5959+                // Check delimiters. If they're not the same, throw error.
5960+                if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
5961+                    throw new Error();
5962+                }
5963+                var years = parseInt(matches[7]);
5964+                var monthName = matches[3];
5965+                var days = parseInt(matches[5]) - 1; // Days are zero indexed.
5966+                var tmpMoment = createMoment(years, monthName, days);
5967+                if (matches.length >= 9 && matches[8] !== undefined) {
5968+                    tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
5969+                }
5970+                m = tmpMoment;
5971+            }
5972+        }
5973+        // Check DAY_MONTHNAME_YEAR, DD(fd)Month(fd)YYYY, '24/July/1992'
5974+        if (m === undefined) {
5975+            var matches = dateString.match(DAY_MONTHNAME_YEAR);
5976+            if (matches && matches.length >= 8) {
5977+                var years = parseInt(matches[7]);
5978+                var monthName = matches[5];
5979+                var days = parseInt(matches[3]) - 1; // Days are zero indexed.
5980+                var firstDelimiter = matches[4].replace(/\s*/g, '');
5981+                var secondDelimiter = matches[6].replace(/\s*/g, '');
5982+                // Check delimiters. If they're not the same, and the first one isn't a space, throw error.
5983+                if (firstDelimiter !== secondDelimiter && firstDelimiter !== "") {
5984+                    throw new Error();
5985+                }
5986+                var tmpMoment = createMoment(years, monthName, days);
5987+                if (matches.length >= 9 && matches[8] !== undefined) {
5988+                    tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
5989+                }
5990+                m = tmpMoment;
5991+            }
5992+        }
5993+        // Check YEAR_MONTHNAME, YYYY(fd)Month, '1992/Aug'
5994+        if (m === undefined) {
5995+            var matches = dateString.match(YEAR_MONTHNAME);
5996+            if (matches && matches.length >= 6) {
5997+                var years = parseInt(matches[3]);
5998+                var monthName = matches[5];
5999+                var tmpMoment = createMoment(years, monthName, 0);
6000+                if (matches[6] !== undefined) {
6001+                    tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
6002+                }
6003+                m = tmpMoment;
6004+            }
6005+        }
6006+        return m;
6007+    };
6008+    /**
6009+     * Parses a string as a date number. Throws error if parsing not possible.
6010+     * @param dateString to parse
6011+     * @returns {number} resulting date
6012+     */
6013+    TypeConverter.stringToDateNumber = function (dateString) {
6014+        // m will be set and valid or invalid, or will remain undefined
6015+        var m;
6016+        try {
6017+            m = TypeConverter.parseStringToMoment(dateString);
6018+        }
6019+        catch (e) {
6020+            throw new Errors_1.ValueError("DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
6021+        }
6022+        if (m === undefined || !m.isValid()) {
6023+            throw new Errors_1.ValueError("DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
6024+        }
6025+        return TypeConverter.momentToDayNumber(m.set('hours', 0).set('minutes', 0).set('seconds', 0));
6026+    };
6027+    /**
6028+     * Converts strings to numbers, returning undefined if string cannot be parsed to number. Examples: "100", "342424",
6029+     * "10%", "33.213131", "41.1231", "10e1", "10E1", "10.44E1", "-$9.29", "+$9.29", "1,000.1", "2000,000,000".
6030+     * For reference see: https://regex101.com/r/PwghnF/9/
6031+     * @param value to parse.
6032+     * @returns {number} or undefined
6033+     */
6034+    TypeConverter.stringToNumber = function (value) {
6035+        function isUndefined(x) {
6036+            return x === undefined;
6037+        }
6038+        function isDefined(x) {
6039+            return x !== undefined;
6040+        }
6041+        var NUMBER_REGEX = /^ *(\+|\-)? *(\$)? *(\+|\-)? *((\d+)?(,\d{3})?(,\d{3})?(,\d{3})?(,\d{3})?)? *(\.)? *(\d*)? *(e|E)? *(\d*)? *(%)? *$/;
6042+        var matches = value.match(NUMBER_REGEX);
6043+        if (matches !== null) {
6044+            var firstSign = matches[1];
6045+            var currency = matches[2];
6046+            var secondSign = matches[3];
6047+            var wholeNumberWithCommas = matches[4];
6048+            var decimalPoint = matches[10];
6049+            var decimalNumber = matches[11];
6050+            var sciNotation = matches[12];
6051+            var sciNotationFactor = matches[13];
6052+            var percentageSign = matches[14];
6053+            // Number is not valid if it is a currency and in scientific notation.
6054+            if (isDefined(currency) && isDefined(sciNotation)) {
6055+                return undefined;
6056+            }
6057+            // Number is not valid if there are two signs.
6058+            if (isDefined(firstSign) && isDefined(secondSign)) {
6059+                return undefined;
6060+            }
6061+            // Number is not valid if we have 'sciNotation' but no 'sciNotationFactor'
6062+            if (isDefined(sciNotation) && isUndefined(sciNotationFactor)) {
6063+                return undefined;
6064+            }
6065+            var activeSign;
6066+            if (isUndefined(firstSign) && isUndefined(secondSign)) {
6067+                activeSign = "+";
6068+            }
6069+            else if (!isUndefined(firstSign)) {
6070+                activeSign = firstSign;
6071+            }
6072+            else {
6073+                activeSign = secondSign;
6074+            }
6075+            var x;
6076+            if (isDefined(wholeNumberWithCommas)) {
6077+                if (isDefined(decimalNumber) && isDefined(decimalNumber)) {
6078+                    // console.log("parsing:", value, activeSign + wholeNumberWithCommas.split(",").join("") + decimalPoint + decimalNumber);
6079+                    x = parseFloat(activeSign + wholeNumberWithCommas.split(",").join("") + decimalPoint + decimalNumber);
6080+                }
6081+                else {
6082+                    // console.log("parsing:", value, activeSign + wholeNumberWithCommas.split(",").join(""))
6083+                    x = parseFloat(activeSign + wholeNumberWithCommas.split(",").join(""));
6084+                }
6085+            }
6086+            else {
6087+                // console.log("parsing:", value, activeSign + "0" + decimalPoint + decimalNumber);
6088+                x = parseFloat(activeSign + "0" + decimalPoint + decimalNumber);
6089+            }
6090+            if (isDefined(sciNotation) && isDefined(sciNotationFactor)) {
6091+                x = x * Math.pow(10, parseInt(sciNotationFactor));
6092+            }
6093+            if (!isUndefined(percentageSign)) {
6094+                x = x * 0.01;
6095+            }
6096+            return x;
6097+        }
6098+    };
6099+    /**
6100+     * Converts any value to a number or throws an error if it cannot coerce it to the number type
6101+     * @param value to convert
6102+     * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
6103+     */
6104+    TypeConverter.valueToNumber = function (value) {
6105+        if (typeof value === "number") {
6106+            return value;
6107+        }
6108+        else if (typeof value === "string") {
6109+            if (value === "") {
6110+                return 0;
6111+            }
6112+            var n = TypeConverter.stringToNumber(value);
6113+            if (n === undefined) {
6114+                throw new Errors_1.ValueError("Function ____ expects number values, but is text and cannot be coerced to a number.");
6115+            }
6116+            return n;
6117+        }
6118+        else if (typeof value === "boolean") {
6119+            return value ? 1 : 0;
6120+        }
6121+        return 0;
6122+    };
6123+    /**
6124+     * Converts any value to a number, defaulting to 0 value in cases in which it cannot coerce it to a number type
6125+     * @param value to conver
6126+     * @returns {number} to return. Will always return a number or 0.
6127+     */
6128+    TypeConverter.valueToNumberGracefully = function (value) {
6129+        try {
6130+            return TypeConverter.valueToNumber(value);
6131+        }
6132+        catch (e) {
6133+            return 0;
6134+        }
6135+    };
6136+    /**
6137+     * Converts any value to a boolean or throws an error if it cannot coerce it to the boolean type.
6138+     * @param value to convert
6139+     * @returns {boolean} to return.
6140+     */
6141+    TypeConverter.valueToBoolean = function (value) {
6142+        if (typeof value === "number") {
6143+            return value !== 0;
6144+        }
6145+        else if (typeof value === "string") {
6146+            throw new Errors_1.ValueError("___ expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.");
6147+        }
6148+        else if (typeof value === "boolean") {
6149+            return value;
6150+        }
6151+    };
6152+    /**
6153+     * Convert a value to string.
6154+     * @param value of any type, including array. array cannot be empty.
6155+     * @returns {string} string representation of value
6156+     */
6157+    TypeConverter.valueToString = function (value) {
6158+        if (typeof value === "number") {
6159+            return value.toString();
6160+        }
6161+        else if (typeof value === "string") {
6162+            return value;
6163+        }
6164+        else if (typeof value === "boolean") {
6165+            return value ? "TRUE" : "FALSE";
6166+        }
6167+    };
6168+    /**
6169+     * Converts a value to a time number; a value between 0 and 1, exclusive on 1.
6170+     * @param value to convert
6171+     * @returns {number} representing a time value
6172+     */
6173+    TypeConverter.valueToTimestampNumber = function (value) {
6174+        if (typeof value === "number") {
6175+            return value;
6176+        }
6177+        else if (typeof value === "string") {
6178+            if (value == "") {
6179+                return 0;
6180+            }
6181+            try {
6182+                return TypeConverter.stringToTimeNumber(value);
6183+            }
6184+            catch (e) {
6185+                if (TypeConverter.canCoerceToNumber(value)) {
6186+                    return TypeConverter.valueToNumber(value);
6187+                }
6188+                throw new Errors_1.ValueError("___ expects number values. But '" + value + "' is a text and cannot be coerced to a number.");
6189+            }
6190+        }
6191+        else if (typeof value === "boolean") {
6192+            return 0; // value between 0 and 1, exclusive on 1.
6193+        }
6194+        return 0;
6195+    };
6196+    /**
6197+     * Returns true if string is number format.
6198+     * @param str to check
6199+     * @returns {boolean}
6200+     */
6201+    TypeConverter.isNumber = function (str) {
6202+        return str.match("\s*(\d+\.?\d*$)|(\.\d+$)|([0-9]{2}%$)|([0-9]{1,}$)") !== null;
6203+    };
6204+    /**
6205+     * Returns true if we can coerce it to the number type.
6206+     * @param value to coerce
6207+     * @returns {boolean} if could be coerced to a number
6208+     */
6209+    TypeConverter.canCoerceToNumber = function (value) {
6210+        if (typeof value === "number" || typeof value === "boolean") {
6211+            return true;
6212+        }
6213+        else if (typeof value === "string") {
6214+            return TypeConverter.isNumber(value);
6215+        }
6216+        return false;
6217+    };
6218+    /**
6219+     * Takes any input type and will throw a REF_ERROR or coerce it into a number.
6220+     * @param input to attempt to coerce into a number
6221+     * @returns {number} number representation of the input
6222+     */
6223+    TypeConverter.firstValueAsNumber = function (input) {
6224+        if (input instanceof Array) {
6225+            if (input.length === 0) {
6226+                throw new Errors_1.RefError("Reference does not exist.");
6227+            }
6228+            return TypeConverter.firstValueAsNumber(input[0]);
6229+        }
6230+        return TypeConverter.valueToNumber(input);
6231+    };
6232+    /**
6233+     * Takes any input type and will throw a REF_ERROR or coerce it into a string.
6234+     * @param input to attempt to coerce into a string
6235+     * @returns {number} number representation of the input
6236+     */
6237+    TypeConverter.firstValueAsString = function (input) {
6238+        if (input instanceof Array) {
6239+            if (input.length === 0) {
6240+                throw new Errors_1.RefError("Reference does not exist.");
6241+            }
6242+            return TypeConverter.firstValueAsString(input[0]);
6243+        }
6244+        return TypeConverter.valueToString(input);
6245+    };
6246+    /**
6247+     * Returns the first value that is not of the type array. Will throw RefError if any empty arrays are passed in.
6248+     * @param input to retrieve first value of
6249+     * @returns {any} any non-array value.
6250+     */
6251+    TypeConverter.firstValue = function (input) {
6252+        if (input instanceof Array) {
6253+            if (input.length === 0) {
6254+                throw new Errors_1.RefError("Reference does not exist.");
6255+            }
6256+            return TypeConverter.firstValue(input[0]);
6257+        }
6258+        return input;
6259+    };
6260+    /**
6261+     * Takes any input type and will throw a REF_ERROR or coerce it into a string.
6262+     * @param input to attempt to coerce into a string
6263+     * @returns {number} number representation of the input
6264+     */
6265+    TypeConverter.firstValueAsBoolean = function (input) {
6266+        if (input instanceof Array) {
6267+            if (input.length === 0) {
6268+                throw new Errors_1.RefError("Reference does not exist.");
6269+            }
6270+            return TypeConverter.firstValueAsBoolean(input[0]);
6271+        }
6272+        return TypeConverter.valueToBoolean(input);
6273+    };
6274+    /**
6275+     * Takes the input type and will throw a REF_ERROR or coerce it into a date number
6276+     * @param input input to attempt to coerce to a date number
6277+     * @param coerceBoolean should a boolean be converted
6278+     * @returns {number} representing a date
6279+     */
6280+    TypeConverter.firstValueAsDateNumber = function (input, coerceBoolean) {
6281+        if (input instanceof Array) {
6282+            if (input.length === 0) {
6283+                throw new Errors_1.RefError("Reference does not exist.");
6284+            }
6285+            return TypeConverter.firstValueAsDateNumber(input[0], coerceBoolean);
6286+        }
6287+        return TypeConverter.valueToDateNumber(input, coerceBoolean);
6288+    };
6289+    /**
6290+     * Takes the input type and will throw a REF_ERROR or coerce it into a time number
6291+     * @param input input to attempt to coerce to a time number
6292+     * @returns {number} representing time of day
6293+     */
6294+    TypeConverter.firstValueAsTimestampNumber = function (input) {
6295+        if (input instanceof Array) {
6296+            if (input.length === 0) {
6297+                throw new Errors_1.RefError("Reference does not exist.");
6298+            }
6299+            return TypeConverter.firstValueAsTimestampNumber(input[0]);
6300+        }
6301+        return TypeConverter.valueToTimestampNumber(input);
6302+    };
6303+    /**
6304+     * Convert a value to date number if possible.
6305+     * @param value to convert
6306+     * @param coerceBoolean should a boolean be converted
6307+     * @returns {number} date
6308+     */
6309+    TypeConverter.valueToDateNumber = function (value, coerceBoolean) {
6310+        if (typeof value === "number") {
6311+            return value;
6312+        }
6313+        else if (typeof value === "string") {
6314+            try {
6315+                return TypeConverter.stringToDateNumber(value);
6316+            }
6317+            catch (e) {
6318+                if (TypeConverter.canCoerceToNumber(value)) {
6319+                    return TypeConverter.valueToNumber(value);
6320+                }
6321+                throw new Errors_1.ValueError("___ expects date values. But '" + value + "' is a text and cannot be coerced to a date.");
6322+            }
6323+        }
6324+        else if (typeof value === "boolean") {
6325+            if (coerceBoolean) {
6326+                return value ? 1 : 0;
6327+            }
6328+            throw new Errors_1.ValueError("___ expects date values. But '" + value + "' is a boolean and cannot be coerced to a date.");
6329+        }
6330+    };
6331+    /**
6332+     * Converts a moment to a date number.
6333+     * @param m to convert
6334+     * @returns {number} date
6335+     */
6336+    TypeConverter.momentToNumber = function (m) {
6337+        return m.diff(this.ORIGIN_MOMENT, "seconds") / this.SECONDS_IN_DAY;
6338+    };
6339+    /**
6340+     * Converts a moment to a date number, floored to the whole day date.
6341+     * @param m to convert
6342+     * @returns {number} date
6343+     */
6344+    TypeConverter.momentToDayNumber = function (m) {
6345+        return Math.floor(TypeConverter.momentToNumber(m));
6346+    };
6347+    /**
6348+     * Converts a number to moment.
6349+     * @param n to convert
6350+     * @returns {Moment} date
6351+     */
6352+    TypeConverter.numberToMoment = function (n) {
6353+        return moment.utc(TypeConverter.ORIGIN_MOMENT).add(n, "days");
6354+    };
6355+    /**
6356+     * Using timestamp units, create a time number between 0 and 1, exclusive on end.
6357+     * @param hours
6358+     * @param minutes
6359+     * @param seconds
6360+     * @returns {number} representing time of day between 0 and 1, exclusive on end.
6361+     */
6362+    TypeConverter.unitsToTimeNumber = function (hours, minutes, seconds) {
6363+        var v = (((hours % 24) * 60 * 60) + ((minutes) * 60) + (seconds)) / 86400;
6364+        return v % 1;
6365+    };
6366+    return TypeConverter;
6367+}());
6368+TypeConverter.ORIGIN_MOMENT = moment.utc([1899, 11, 30]).startOf("day");
6369+TypeConverter.SECONDS_IN_DAY = 86400;
6370+exports.TypeConverter = TypeConverter;
6371+/**
6372+ * Catches divide by zero situations and throws them as errors
6373+ * @param n number to check
6374+ * @returns {number} n as long as it's not zero.
6375+ */
6376+var checkForDevideByZero = function (n) {
6377+    n = +n; // Coerce to number.
6378+    if (!n) {
6379+        throw new Errors_1.DivZeroError("Evaluation of function caused a divide by zero error.");
6380+    }
6381+    return n;
6382+};
6383+exports.checkForDevideByZero = checkForDevideByZero;
6384diff --git a/dist/parser.js b/dist/parser.js
6385new file mode 100644
6386index 0000000..4206cfd
6387--- /dev/null
6388+++ b/dist/parser.js
6389@@ -0,0 +1,1006 @@
6390+/* parser generated by jison 0.4.15 */
6391+/*
6392+ Returns a Parser object of the following structure:
6393+
6394+ Parser: {
6395+ yy: {}
6396+ }
6397+
6398+ Parser.prototype: {
6399+ yy: {},
6400+ trace: function(),
6401+ symbols_: {associative list: name ==> number},
6402+ terminals_: {associative list: number ==> name},
6403+ productions_: [...],
6404+ performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
6405+ table: [...],
6406+ defaultActions: {...},
6407+ parseError: function(str, hash),
6408+ parse: function(input),
6409+
6410+ lexer: {
6411+ EOF: 1,
6412+ parseError: function(str, hash),
6413+ setInput: function(input),
6414+ input: function(),
6415+ unput: function(str),
6416+ more: function(),
6417+ less: function(n),
6418+ pastInput: function(),
6419+ upcomingInput: function(),
6420+ showPosition: function(),
6421+ test_match: function(regex_match_array, rule_index),
6422+ next: function(),
6423+ lex: function(),
6424+ begin: function(condition),
6425+ popState: function(),
6426+ _currentRules: function(),
6427+ topState: function(),
6428+ pushState: function(condition),
6429+
6430+ options: {
6431+ ranges: boolean           (optional: true ==> token location info will include a .range[] member)
6432+ flex: boolean             (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
6433+ 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)
6434+ },
6435+
6436+ performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
6437+ rules: [...],
6438+ conditions: {associative list: name ==> set},
6439+ }
6440+ }
6441+
6442+
6443+ token location info (@$, _$, etc.): {
6444+ first_line: n,
6445+ last_line: n,
6446+ first_column: n,
6447+ last_column: n,
6448+ range: [start_number, end_number]       (where the numbers are indexes into the input string, regular zero-based)
6449+ }
6450+
6451+
6452+ the parseError function receives a 'hash' object with these members for lexer and parser errors: {
6453+ text:        (matched text)
6454+ token:       (the produced terminal token, if any)
6455+ line:        (yylineno)
6456+ }
6457+ while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
6458+ loc:         (yylloc)
6459+ expected:    (string describing the set of expected tokens)
6460+ recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
6461+ }
6462+ */
6463+var Parser = (function(){
6464+  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];
6465+  var parser = {trace: function trace() { },
6466+    yy: {},
6467+    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},
6468+    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:"!"},
6469+    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]],
6470+    performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
6471+      /* this == yyval */
6472+
6473+      var $0 = $$.length - 1;
6474+      switch (yystate) {
6475+        case 1:
6476+
6477+          return $$[$0-1];
6478+
6479+          break;
6480+        case 2:
6481+
6482+          this.$ = yy.handler.helper.callVariable.call(this, $$[$0]);
6483+
6484+          break;
6485+        case 3:
6486+
6487+          this.$ = yy.handler.time.call(yy.obj, $$[$0], true);
6488+
6489+          break;
6490+        case 4:
6491+
6492+          this.$ = yy.handler.time.call(yy.obj, $$[$0]);
6493+
6494+          break;
6495+        case 5:
6496+
6497+          this.$ = yy.handler.helper.number($$[$0]);
6498+
6499+          break;
6500+        case 6:
6501+
6502+          this.$ = yy.handler.helper.string($$[$0]);
6503+
6504+          break;
6505+        case 7:
6506+
6507+          this.$ = yy.handler.helper.specialMatch('&', $$[$0-2], $$[$0]);
6508+
6509+          break;
6510+        case 8:
6511+
6512+          this.$ = yy.handler.helper.logicMatch('=', $$[$0-2], $$[$0]);
6513+
6514+          break;
6515+        case 9:
6516+
6517+          this.$ = yy.handler.helper.mathMatch('+', $$[$0-2], $$[$0]);
6518+
6519+          break;
6520+        case 10:
6521+
6522+          this.$ = yy.handler.helper.number($$[$0-1]);
6523+
6524+          break;
6525+        case 11:
6526+
6527+          this.$ = yy.handler.helper.logicMatch('<=', $$[$0-3], $$[$0]);
6528+
6529+          break;
6530+        case 12:
6531+
6532+          this.$ = yy.handler.helper.logicMatch('>=', $$[$0-3], $$[$0]);
6533+
6534+          break;
6535+        case 13:
6536+
6537+          this.$ = yy.handler.helper.logicMatch('<>', $$[$0-3], $$[$0]);
6538+
6539+          break;
6540+        case 14:
6541+
6542+          this.$ = yy.handler.helper.logicMatch('NOT', $$[$0-2], $$[$0]);
6543+
6544+          break;
6545+        case 15:
6546+
6547+          this.$ = yy.handler.helper.logicMatch('>', $$[$0-2], $$[$0]);
6548+
6549+          break;
6550+        case 16:
6551+
6552+          this.$ = yy.handler.helper.logicMatch('<', $$[$0-2], $$[$0]);
6553+
6554+          break;
6555+        case 17:
6556+
6557+          this.$ = yy.handler.helper.mathMatch('-', $$[$0-2], $$[$0]);
6558+
6559+          break;
6560+        case 18:
6561+
6562+          this.$ = yy.handler.helper.mathMatch('*', $$[$0-2], $$[$0]);
6563+
6564+          break;
6565+        case 19:
6566+
6567+          this.$ = yy.handler.helper.mathMatch('/', $$[$0-2], $$[$0]);
6568+
6569+          break;
6570+        case 20:
6571+
6572+          this.$ = yy.handler.helper.mathMatch('^', $$[$0-2], $$[$0]);
6573+
6574+          break;
6575+        case 21:
6576+
6577+          var n1 = yy.handler.helper.numberInverted($$[$0]);
6578+          this.$ = n1;
6579+          if (isNaN(this.$)) {
6580+            this.$ = 0;
6581+          }
6582+
6583+          break;
6584+        case 22:
6585+
6586+          var n1 = yy.handler.helper.number($$[$0]);
6587+          this.$ = n1;
6588+          if (isNaN(this.$)) {
6589+            this.$ = 0;
6590+          }
6591+
6592+          break;
6593+        case 23:
6594+
6595+          this.$ = yy.handler.helper.callFunction.call(this, $$[$0-2], '');
6596+
6597+          break;
6598+        case 24:
6599+
6600+          this.$ = yy.handler.helper.callFunction.call(this, $$[$0-3], $$[$0-1]);
6601+
6602+          break;
6603+        case 28:
6604+
6605+          this.$ = yy.handler.helper.fixedCellValue.call(yy.obj, $$[$0]);
6606+
6607+          break;
6608+        case 29:
6609+
6610+          this.$ = yy.handler.helper.fixedCellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
6611+
6612+          break;
6613+        case 30:
6614+
6615+          this.$ = yy.handler.helper.cellValue.call(yy.obj, $$[$0]);
6616+
6617+          break;
6618+        case 31:
6619+
6620+          this.$ = yy.handler.helper.cellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
6621+
6622+          break;
6623+        case 32:
6624+
6625+          if (yy.handler.utils.isArray($$[$0])) {
6626+            this.$ = $$[$0];
6627+          } else {
6628+            this.$ = [$$[$0]];
6629+          }
6630+
6631+          break;
6632+        case 33:
6633+
6634+          var result = [],
6635+            arr = eval("[" + yytext + "]");
6636+
6637+          arr.forEach(function (item) {
6638+            result.push(item);
6639+          });
6640+
6641+          this.$ = result;
6642+
6643+          break;
6644+        case 34: case 35:
6645+
6646+        $$[$0-2].push($$[$0]);
6647+        this.$ = $$[$0-2];
6648+
6649+        break;
6650+        case 36:
6651+
6652+          this.$ = [$$[$0]];
6653+
6654+          break;
6655+        case 37:
6656+
6657+          this.$ = (yy.handler.utils.isArray($$[$0-2]) ? $$[$0-2] : [$$[$0-2]]);
6658+          this.$.push($$[$0]);
6659+
6660+          break;
6661+        case 38:
6662+
6663+          this.$ = $$[$0];
6664+
6665+          break;
6666+        case 39:
6667+
6668+          this.$ = ($$[$0-2] + '.' + $$[$0]) * 1;
6669+
6670+          break;
6671+        case 40:
6672+
6673+          this.$ = $$[$0-1] * 0.01;
6674+
6675+          break;
6676+        case 41: case 42:
6677+
6678+        this.$ = $$[$0-2] + $$[$0-1] + $$[$0];
6679+
6680+        break;
6681+      }
6682+    },
6683+    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})],
6684+    defaultActions: {19:[2,1]},
6685+    parseError: function parseError(str, hash) {
6686+      if (hash.recoverable) {
6687+        this.trace(str);
6688+      } else {
6689+        throw new Error(str);
6690+      }
6691+    },
6692+    parse: function parse(input) {
6693+      var self = this,
6694+        stack = [0],
6695+        tstack = [], // token stack
6696+        vstack = [null], // semantic value stack
6697+        lstack = [], // location stack
6698+        table = this.table,
6699+        yytext = '',
6700+        yylineno = 0,
6701+        yyleng = 0,
6702+        recovering = 0,
6703+        TERROR = 2,
6704+        EOF = 1;
6705+
6706+      var args = lstack.slice.call(arguments, 1);
6707+
6708+      //this.reductionCount = this.shiftCount = 0;
6709+
6710+      var lexer = Object.create(this.lexer);
6711+      var sharedState = { yy: {} };
6712+      // copy state
6713+      for (var k in this.yy) {
6714+        if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
6715+          sharedState.yy[k] = this.yy[k];
6716+        }
6717+      }
6718+
6719+      lexer.setInput(input, sharedState.yy);
6720+      sharedState.yy.lexer = lexer;
6721+      sharedState.yy.parser = this;
6722+      if (typeof lexer.yylloc == 'undefined') {
6723+        lexer.yylloc = {};
6724+      }
6725+      var yyloc = lexer.yylloc;
6726+      lstack.push(yyloc);
6727+
6728+      var ranges = lexer.options && lexer.options.ranges;
6729+
6730+      if (typeof sharedState.yy.parseError === 'function') {
6731+        this.parseError = sharedState.yy.parseError;
6732+      } else {
6733+        this.parseError = Object.getPrototypeOf(this).parseError;
6734+      }
6735+
6736+      function popStack (n) {
6737+        stack.length = stack.length - 2 * n;
6738+        vstack.length = vstack.length - n;
6739+        lstack.length = lstack.length - n;
6740+      }
6741+
6742+      _token_stack:
6743+        function lex() {
6744+          var token;
6745+          token = lexer.lex() || EOF;
6746+          // if token isn't its numeric value, convert
6747+          if (typeof token !== 'number') {
6748+            token = self.symbols_[token] || token;
6749+          }
6750+          return token;
6751+        }
6752+
6753+      var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
6754+      while (true) {
6755+        // retreive state number from top of stack
6756+        state = stack[stack.length - 1];
6757+
6758+        // use default actions if available
6759+        if (this.defaultActions[state]) {
6760+          action = this.defaultActions[state];
6761+        } else {
6762+          if (symbol === null || typeof symbol == 'undefined') {
6763+            symbol = lex();
6764+          }
6765+          // read action for current state and first input
6766+          action = table[state] && table[state][symbol];
6767+        }
6768+
6769+        _handle_error:
6770+          // handle parse error
6771+          if (typeof action === 'undefined' || !action.length || !action[0]) {
6772+            var error_rule_depth;
6773+            var errStr = '';
6774+
6775+            // Return the rule stack depth where the nearest error rule can be found.
6776+            // Return FALSE when no error recovery rule was found.
6777+            function locateNearestErrorRecoveryRule(state) {
6778+              var stack_probe = stack.length - 1;
6779+              var depth = 0;
6780+
6781+              // try to recover from error
6782+              for(;;) {
6783+                // check for error recovery rule in this state
6784+                if ((TERROR.toString()) in table[state]) {
6785+                  return depth;
6786+                }
6787+                if (state === 0 || stack_probe < 2) {
6788+                  return false; // No suitable error recovery rule available.
6789+                }
6790+                stack_probe -= 2; // popStack(1): [symbol, action]
6791+                state = stack[stack_probe];
6792+                ++depth;
6793+              }
6794+            }
6795+
6796+            if (!recovering) {
6797+              // first see if there's any chance at hitting an error recovery rule:
6798+              error_rule_depth = locateNearestErrorRecoveryRule(state);
6799+
6800+              // Report error
6801+              expected = [];
6802+              for (p in table[state]) {
6803+                if (this.terminals_[p] && p > TERROR) {
6804+                  expected.push("'"+this.terminals_[p]+"'");
6805+                }
6806+              }
6807+              if (lexer.showPosition) {
6808+                errStr = 'Parse error on line '+(yylineno+1)+":\n"+lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + (this.terminals_[symbol] || symbol)+ "'";
6809+              } else {
6810+                errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
6811+                  (symbol == EOF ? "end of input" :
6812+                    ("'"+(this.terminals_[symbol] || symbol)+"'"));
6813+              }
6814+              this.parseError(errStr, {
6815+                text: lexer.match,
6816+                token: this.terminals_[symbol] || symbol,
6817+                line: lexer.yylineno,
6818+                loc: yyloc,
6819+                expected: expected,
6820+                recoverable: (error_rule_depth !== false)
6821+              });
6822+            } else if (preErrorSymbol !== EOF) {
6823+              error_rule_depth = locateNearestErrorRecoveryRule(state);
6824+            }
6825+
6826+            // just recovered from another error
6827+            if (recovering == 3) {
6828+              if (symbol === EOF || preErrorSymbol === EOF) {
6829+                throw new Error(errStr || 'Parsing halted while starting to recover from another error.');
6830+              }
6831+
6832+              // discard current lookahead and grab another
6833+              yyleng = lexer.yyleng;
6834+              yytext = lexer.yytext;
6835+              yylineno = lexer.yylineno;
6836+              yyloc = lexer.yylloc;
6837+              symbol = lex();
6838+            }
6839+
6840+            // try to recover from error
6841+            if (error_rule_depth === false) {
6842+              throw new Error(errStr || 'Parsing halted. No suitable error recovery rule available.');
6843+            }
6844+            popStack(error_rule_depth);
6845+
6846+            preErrorSymbol = (symbol == TERROR ? null : symbol); // save the lookahead token
6847+            symbol = TERROR;         // insert generic error symbol as new lookahead
6848+            state = stack[stack.length-1];
6849+            action = table[state] && table[state][TERROR];
6850+            recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
6851+          }
6852+
6853+        // this shouldn't happen, unless resolve defaults are off
6854+        if (action[0] instanceof Array && action.length > 1) {
6855+          throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
6856+        }
6857+
6858+        switch (action[0]) {
6859+          case 1: // shift
6860+            //this.shiftCount++;
6861+
6862+            stack.push(symbol);
6863+            vstack.push(lexer.yytext);
6864+            lstack.push(lexer.yylloc);
6865+            stack.push(action[1]); // push state
6866+            symbol = null;
6867+            if (!preErrorSymbol) { // normal execution/no error
6868+              yyleng = lexer.yyleng;
6869+              yytext = lexer.yytext;
6870+              yylineno = lexer.yylineno;
6871+              yyloc = lexer.yylloc;
6872+              if (recovering > 0) {
6873+                recovering--;
6874+              }
6875+            } else {
6876+              // error just occurred, resume old lookahead f/ before error
6877+              symbol = preErrorSymbol;
6878+              preErrorSymbol = null;
6879+            }
6880+            break;
6881+
6882+          case 2:
6883+            // reduce
6884+            //this.reductionCount++;
6885+
6886+            len = this.productions_[action[1]][1];
6887+
6888+            // perform semantic action
6889+            yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
6890+            // default location, uses first token for firsts, last for lasts
6891+            yyval._$ = {
6892+              first_line: lstack[lstack.length-(len||1)].first_line,
6893+              last_line: lstack[lstack.length-1].last_line,
6894+              first_column: lstack[lstack.length-(len||1)].first_column,
6895+              last_column: lstack[lstack.length-1].last_column
6896+            };
6897+            if (ranges) {
6898+              yyval._$.range = [lstack[lstack.length-(len||1)].range[0], lstack[lstack.length-1].range[1]];
6899+            }
6900+            r = this.performAction.apply(yyval, [yytext, yyleng, yylineno, sharedState.yy, action[1], vstack, lstack].concat(args));
6901+
6902+            if (typeof r !== 'undefined') {
6903+              return r;
6904+            }
6905+
6906+            // pop off stack
6907+            if (len) {
6908+              stack = stack.slice(0,-1*len*2);
6909+              vstack = vstack.slice(0, -1*len);
6910+              lstack = lstack.slice(0, -1*len);
6911+            }
6912+
6913+            stack.push(this.productions_[action[1]][0]);    // push nonterminal (reduce)
6914+            vstack.push(yyval.$);
6915+            lstack.push(yyval._$);
6916+            // goto new state = table[STATE][NONTERMINAL]
6917+            newState = table[stack[stack.length-2]][stack[stack.length-1]];
6918+            stack.push(newState);
6919+            break;
6920+
6921+          case 3:
6922+            // accept
6923+            return true;
6924+        }
6925+
6926+      }
6927+
6928+      return true;
6929+    }};
6930+
6931+  /* generated by jison-lex 0.3.4 */
6932+  var lexer = (function(){
6933+    var lexer = ({
6934+
6935+      EOF:1,
6936+
6937+      parseError:function parseError(str, hash) {
6938+        if (this.yy.parser) {
6939+          this.yy.parser.parseError(str, hash);
6940+        } else {
6941+          throw new Error(str);
6942+        }
6943+      },
6944+
6945+// resets the lexer, sets new input
6946+      setInput:function (input, yy) {
6947+        this.yy = yy || this.yy || {};
6948+        this._input = input;
6949+        this._more = this._backtrack = this.done = false;
6950+        this.yylineno = this.yyleng = 0;
6951+        this.yytext = this.matched = this.match = '';
6952+        this.conditionStack = ['INITIAL'];
6953+        this.yylloc = {
6954+          first_line: 1,
6955+          first_column: 0,
6956+          last_line: 1,
6957+          last_column: 0
6958+        };
6959+        if (this.options.ranges) {
6960+          this.yylloc.range = [0,0];
6961+        }
6962+        this.offset = 0;
6963+        return this;
6964+      },
6965+
6966+// consumes and returns one char from the input
6967+      input:function () {
6968+        var ch = this._input[0];
6969+        this.yytext += ch;
6970+        this.yyleng++;
6971+        this.offset++;
6972+        this.match += ch;
6973+        this.matched += ch;
6974+        var lines = ch.match(/(?:\r\n?|\n).*/g);
6975+        if (lines) {
6976+          this.yylineno++;
6977+          this.yylloc.last_line++;
6978+        } else {
6979+          this.yylloc.last_column++;
6980+        }
6981+        if (this.options.ranges) {
6982+          this.yylloc.range[1]++;
6983+        }
6984+
6985+        this._input = this._input.slice(1);
6986+        return ch;
6987+      },
6988+
6989+// unshifts one char (or a string) into the input
6990+      unput:function (ch) {
6991+        var len = ch.length;
6992+        var lines = ch.split(/(?:\r\n?|\n)/g);
6993+
6994+        this._input = ch + this._input;
6995+        this.yytext = this.yytext.substr(0, this.yytext.length - len);
6996+        //this.yyleng -= len;
6997+        this.offset -= len;
6998+        var oldLines = this.match.split(/(?:\r\n?|\n)/g);
6999+        this.match = this.match.substr(0, this.match.length - 1);
7000+        this.matched = this.matched.substr(0, this.matched.length - 1);
7001+
7002+        if (lines.length - 1) {
7003+          this.yylineno -= lines.length - 1;
7004+        }
7005+        var r = this.yylloc.range;
7006+
7007+        this.yylloc = {
7008+          first_line: this.yylloc.first_line,
7009+          last_line: this.yylineno + 1,
7010+          first_column: this.yylloc.first_column,
7011+          last_column: lines ?
7012+          (lines.length === oldLines.length ? this.yylloc.first_column : 0)
7013+          + oldLines[oldLines.length - lines.length].length - lines[0].length :
7014+          this.yylloc.first_column - len
7015+        };
7016+
7017+        if (this.options.ranges) {
7018+          this.yylloc.range = [r[0], r[0] + this.yyleng - len];
7019+        }
7020+        this.yyleng = this.yytext.length;
7021+        return this;
7022+      },
7023+
7024+// When called from action, caches matched text and appends it on next action
7025+      more:function () {
7026+        this._more = true;
7027+        return this;
7028+      },
7029+
7030+// 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.
7031+      reject:function () {
7032+        if (this.options.backtrack_lexer) {
7033+          this._backtrack = true;
7034+        } else {
7035+          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(), {
7036+            text: "",
7037+            token: null,
7038+            line: this.yylineno
7039+          });
7040+
7041+        }
7042+        return this;
7043+      },
7044+
7045+// retain first n characters of the match
7046+      less:function (n) {
7047+        this.unput(this.match.slice(n));
7048+      },
7049+
7050+// displays already matched input, i.e. for error messages
7051+      pastInput:function () {
7052+        var past = this.matched.substr(0, this.matched.length - this.match.length);
7053+        return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
7054+      },
7055+
7056+// displays upcoming input, i.e. for error messages
7057+      upcomingInput:function () {
7058+        var next = this.match;
7059+        if (next.length < 20) {
7060+          next += this._input.substr(0, 20-next.length);
7061+        }
7062+        return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
7063+      },
7064+
7065+// displays the character position where the lexing error occurred, i.e. for error messages
7066+      showPosition:function () {
7067+        var pre = this.pastInput();
7068+        var c = new Array(pre.length + 1).join("-");
7069+        return pre + this.upcomingInput() + "\n" + c + "^";
7070+      },
7071+
7072+// test the lexed token: return FALSE when not a match, otherwise return token
7073+      test_match:function (match, indexed_rule) {
7074+        var token,
7075+          lines,
7076+          backup;
7077+
7078+        if (this.options.backtrack_lexer) {
7079+          // save context
7080+          backup = {
7081+            yylineno: this.yylineno,
7082+            yylloc: {
7083+              first_line: this.yylloc.first_line,
7084+              last_line: this.last_line,
7085+              first_column: this.yylloc.first_column,
7086+              last_column: this.yylloc.last_column
7087+            },
7088+            yytext: this.yytext,
7089+            match: this.match,
7090+            matches: this.matches,
7091+            matched: this.matched,
7092+            yyleng: this.yyleng,
7093+            offset: this.offset,
7094+            _more: this._more,
7095+            _input: this._input,
7096+            yy: this.yy,
7097+            conditionStack: this.conditionStack.slice(0),
7098+            done: this.done
7099+          };
7100+          if (this.options.ranges) {
7101+            backup.yylloc.range = this.yylloc.range.slice(0);
7102+          }
7103+        }
7104+
7105+        lines = match[0].match(/(?:\r\n?|\n).*/g);
7106+        if (lines) {
7107+          this.yylineno += lines.length;
7108+        }
7109+        this.yylloc = {
7110+          first_line: this.yylloc.last_line,
7111+          last_line: this.yylineno + 1,
7112+          first_column: this.yylloc.last_column,
7113+          last_column: lines ?
7114+          lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
7115+          this.yylloc.last_column + match[0].length
7116+        };
7117+        this.yytext += match[0];
7118+        this.match += match[0];
7119+        this.matches = match;
7120+        this.yyleng = this.yytext.length;
7121+        if (this.options.ranges) {
7122+          this.yylloc.range = [this.offset, this.offset += this.yyleng];
7123+        }
7124+        this._more = false;
7125+        this._backtrack = false;
7126+        this._input = this._input.slice(match[0].length);
7127+        this.matched += match[0];
7128+        token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
7129+        if (this.done && this._input) {
7130+          this.done = false;
7131+        }
7132+        if (token) {
7133+          return token;
7134+        } else if (this._backtrack) {
7135+          // recover context
7136+          for (var k in backup) {
7137+            this[k] = backup[k];
7138+          }
7139+          return false; // rule action called reject() implying the next rule should be tested instead.
7140+        }
7141+        return false;
7142+      },
7143+
7144+// return next match in input
7145+      next:function () {
7146+        if (this.done) {
7147+          return this.EOF;
7148+        }
7149+        if (!this._input) {
7150+          this.done = true;
7151+        }
7152+
7153+        var token,
7154+          match,
7155+          tempMatch,
7156+          index;
7157+        if (!this._more) {
7158+          this.yytext = '';
7159+          this.match = '';
7160+        }
7161+        var rules = this._currentRules();
7162+        for (var i = 0; i < rules.length; i++) {
7163+          tempMatch = this._input.match(this.rules[rules[i]]);
7164+          if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
7165+            match = tempMatch;
7166+            index = i;
7167+            if (this.options.backtrack_lexer) {
7168+              token = this.test_match(tempMatch, rules[i]);
7169+              if (token !== false) {
7170+                return token;
7171+              } else if (this._backtrack) {
7172+                match = false;
7173+                continue; // rule action called reject() implying a rule MISmatch.
7174+              } else {
7175+                // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
7176+                return false;
7177+              }
7178+            } else if (!this.options.flex) {
7179+              break;
7180+            }
7181+          }
7182+        }
7183+        if (match) {
7184+          token = this.test_match(match, rules[index]);
7185+          if (token !== false) {
7186+            return token;
7187+          }
7188+          // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
7189+          return false;
7190+        }
7191+        if (this._input === "") {
7192+          return this.EOF;
7193+        } else {
7194+          return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
7195+            text: "",
7196+            token: null,
7197+            line: this.yylineno
7198+          });
7199+        }
7200+      },
7201+
7202+// return next match that has a token
7203+      lex:function lex() {
7204+        var r = this.next();
7205+        if (r) {
7206+          return r;
7207+        } else {
7208+          return this.lex();
7209+        }
7210+      },
7211+
7212+// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
7213+      begin:function begin(condition) {
7214+        this.conditionStack.push(condition);
7215+      },
7216+
7217+// pop the previously active lexer condition state off the condition stack
7218+      popState:function popState() {
7219+        var n = this.conditionStack.length - 1;
7220+        if (n > 0) {
7221+          return this.conditionStack.pop();
7222+        } else {
7223+          return this.conditionStack[0];
7224+        }
7225+      },
7226+
7227+// produce the lexer rule set which is active for the currently active lexer condition state
7228+      _currentRules:function _currentRules() {
7229+        if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
7230+          return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
7231+        } else {
7232+          return this.conditions["INITIAL"].rules;
7233+        }
7234+      },
7235+
7236+// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
7237+      topState:function topState(n) {
7238+        n = this.conditionStack.length - 1 - Math.abs(n || 0);
7239+        if (n >= 0) {
7240+          return this.conditionStack[n];
7241+        } else {
7242+          return "INITIAL";
7243+        }
7244+      },
7245+
7246+// alias for begin(condition)
7247+      pushState:function pushState(condition) {
7248+        this.begin(condition);
7249+      },
7250+
7251+// return the number of states currently on the stack
7252+      stateStackSize:function stateStackSize() {
7253+        return this.conditionStack.length;
7254+      },
7255+      options: {},
7256+      performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
7257+        var YYSTATE=YY_START;
7258+        switch($avoiding_name_collisions) {
7259+          case 0:/* skip whitespace */
7260+            break;
7261+          case 1:return 10;
7262+            break;
7263+          case 2:return 10;
7264+            break;
7265+          case 3:return 23;
7266+            break;
7267+          case 4:return 7;
7268+            break;
7269+          case 5:return 8;
7270+            break;
7271+          case 6:
7272+            //if (yy.obj.type == 'cell') return 26;
7273+            //return 32;
7274+            return 26
7275+
7276+            break;
7277+          case 7:
7278+            //if (yy.obj.type == 'cell') return 28;
7279+            //return 32;
7280+            return 28;
7281+
7282+            break;
7283+          case 8:return 23;
7284+            break;
7285+          case 9:return 32;
7286+            break;
7287+          case 10:return 32;
7288+            break;
7289+          case 11:return 34;
7290+            break;
7291+          case 12:return 29;
7292+            break;
7293+          case 13:/* skip whitespace */
7294+            break;
7295+          case 14:return 11;
7296+            break;
7297+          case 15:return ' ';
7298+            break;
7299+          case 16:return 33;
7300+            break;
7301+          case 17:return 27;
7302+            break;
7303+          case 18:return 30;
7304+            break;
7305+          case 19:return 31;
7306+            break;
7307+          case 20:return 20;
7308+            break;
7309+          case 21:return 21;
7310+            break;
7311+          case 22:return 19;
7312+            break;
7313+          case 23:return 13;
7314+            break;
7315+          case 24:return 22;
7316+            break;
7317+          case 25:return 14;
7318+            break;
7319+          case 26:return 15;
7320+            break;
7321+          case 27:return 17;
7322+            break;
7323+          case 28:return 16;
7324+            break;
7325+          case 29:return 18;
7326+            break;
7327+          case 30:return '"';
7328+            break;
7329+          case 31:return "'";
7330+            break;
7331+          case 32:return "!";
7332+            break;
7333+          case 33:return 12;
7334+            break;
7335+          case 34:return 35;
7336+            break;
7337+          case 35:return 36;
7338+            break;
7339+          case 36:return 5;
7340+            break;
7341+        }
7342+      },
7343+      // NOTE: Alterations made in some regular-expressions to allow for formulas containing dot-notation. Eg: F.INV
7344+      rules: [ /^(?:\s+)/,
7345+        /^(?:"(\\["]|[^"])*")/,
7346+        /^(?:'(\\[']|[^'])*')/,
7347+        /^(?:[A-Za-z.]{1,}[A-Za-z_0-9]+(?=[(]))/, // Changed from /^(?:[A-Za-z]{1,}[A-Za-z_0-9]+(?=[(]))/
7348+        /^(?:([0]?[1-9]|1[0-2])[:][0-5][0-9]([:][0-5][0-9])?[ ]?(AM|am|aM|Am|PM|pm|pM|Pm))/,
7349+        /^(?:([0]?[0-9]|1[0-9]|2[0-3])[:][0-5][0-9]([:][0-5][0-9])?)/,
7350+        /^(?:\$[A-Za-z]+\$[0-9]+)/,
7351+        /^(?:[A-Za-z]+[0-9]+)/,
7352+        /^(?:[A-Za-z.]+(?=[(]))/, //Changed from /^(?:[A-Za-z.]+(?=[(]))/
7353+        /^(?:[A-Za-z]{1,}[A-Za-z_0-9]+)/,
7354+        /^(?:[A-Za-z_]+)/,
7355+        /^(?:[0-9]+)/,
7356+        /^(?:\[(.*)?\])/,
7357+        /^(?:\$)/,
7358+        /^(?:&)/,
7359+        /^(?: )/,
7360+        /^(?:[.])/,
7361+        /^(?::)/,
7362+        /^(?:;)/,
7363+        /^(?:,)/,
7364+        /^(?:\*)/,
7365+        /^(?:\/)/,
7366+        /^(?:-)/,
7367+        /^(?:\+)/,
7368+        /^(?:\^)/,
7369+        /^(?:\()/,
7370+        /^(?:\))/,
7371+        /^(?:>)/,
7372+        /^(?:<)/,
7373+        /^(?:NOT\b)/,
7374+        /^(?:")/,
7375+        /^(?:')/,
7376+        /^(?:!)/,
7377+        /^(?:=)/,
7378+        /^(?:%)/,
7379+        /^(?:[#])/,
7380+        /^(?:$)/ ],
7381+      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}}
7382+    });
7383+    return lexer;
7384+  })();
7385+  parser.lexer = lexer;
7386+  function Parser () {
7387+    this.yy = {};
7388+  }
7389+  Parser.prototype = parser;parser.Parser = Parser;
7390+  return new Parser;
7391+})();
7392+
7393+module.exports = {
7394+  Parser: Parser
7395+};
7396diff --git a/package.json b/package.json
7397index 04691c2..5038be5 100644
7398--- a/package.json
7399+++ b/package.json
7400@@ -3,15 +3,19 @@
7401   "version": "1.0.0",
7402   "description": "TypeScript/javascript implementation of a spreadsheet.",
7403   "scripts": {
7404-    "clean": "rm -rf output/* && rm -rf test_output/*",
7405-    "build": "tsc && cp lib/parser.js output/",
7406+    "clean": "rm -rf dist/* && rm -rf test_output/*",
7407+    "build": "tsc && cp lib/parser.js dist/",
7408     "docs": "./docs.sh src/Formulas",
7409     "test": "./tests.sh",
7410     "test:quiet": "./tests.sh | grep -v Test:"
7411   },
7412   "author": "vogtb <bvogt at gmail.com>",
7413   "license": "MIT",
7414+  "main": "dist/Sheet.js",
7415   "dependencies": {
7416     "moment": "^2.17.1"
7417+  },
7418+  "devDependencies": {
7419+    "typescript": "^2.3.2"
7420   }
7421 }
7422diff --git a/src/Main.ts b/src/Main.ts
7423deleted file mode 100644
7424index 68f7753..0000000
7425--- a/src/Main.ts
7426+++ /dev/null
7427@@ -1,13 +0,0 @@
7428-import { Sheet } from "./Sheet";
7429-
7430-var input = [
7431-  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "=SUM(A1:D1, H1)"],
7432-  [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "=MAX(A2:J2)"],
7433-  [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "=MIN(A3:J3)"],
7434-  [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "=AVERAGE(A4:J4)"],
7435-  [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "=SUMIF(A5:J5,'>5')"],
7436-  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "=SUM(K1, K2, K3, K4)"]
7437-];
7438-var sheet = new Sheet();
7439-sheet.load(input);
7440-console.log(sheet.toString());
7441diff --git a/src/Sheet.ts b/src/Sheet.ts
7442index 71780af..59c2346 100644
7443--- a/src/Sheet.ts
7444+++ b/src/Sheet.ts
7445@@ -1,9 +1,22 @@
7446 /// <reference path="parser.d.ts"/>
7447-import { Parser } from "./Parser";
7448-import { Cell } from "./Cell"
7449-import { DivZeroError, RefError, NameError } from "./Errors"
7450-import { Formulas } from "./Formulas";
7451-import { TypeConverter } from "./Utilities/TypeConverter";
7452+import {
7453+  Parser
7454+} from "./Parser";
7455+import {
7456+  Cell
7457+} from "./Cell";
7458+import {
7459+  DivZeroError,
7460+  RefError,
7461+  NameError
7462+} from "./Errors";
7463+import {
7464+  Formulas
7465+} from "./Formulas";
7466+import * as AllFormulas from "./Formulas/AllFormulas";
7467+import {
7468+  TypeConverter
7469+} from "./Utilities/TypeConverter";
7470 
7471 
7472 /**
7473@@ -596,5 +609,6 @@ var Sheet = (function () {
7474 });
7475 
7476 export {
7477-  Sheet
7478+  Sheet,
7479+  AllFormulas
7480 }
7481\ No newline at end of file
7482diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
7483index ef42e40..69142bc 100644
7484--- a/tests/SheetFormulaTest.ts
7485+++ b/tests/SheetFormulaTest.ts
7486@@ -559,13 +559,12 @@ test("Sheet numbers/math", function(){
7487   assertFormulaEquals('="10.111111" + 0', 10.111111);
7488   assertFormulaEquals('= 10%', 0.1);
7489   assertFormulaEquals('= 10% + 1', 1.1);
7490-  // TODO: These fail
7491-  // assertFormulaEquals('="10e1" + 0', 100);
7492-  // assertFormulaEquals('="1,000,000" + 0', 1000000);
7493-  // assertFormulaEqualsError('= "10e" + 10', VALUE_ERROR); // TODO: Should fail, but doesn't because 10e parses to a string
7494-  // assertFormulaEquals('="+$10.00" + 0', 10);
7495-  // assertFormulaEquals('="-$10.00" + 0', -10);
7496-  // assertFormulaEquals('="$+10.00" + 0', 10);
7497-  // assertFormulaEquals('="$-10.00" + 0', -10);
7498+  assertFormulaEquals('="10e1" + 0', 100);
7499+  assertFormulaEquals('="1,000,000" + 0', 1000000);
7500+  assertFormulaEqualsError('= "10e" + 10', VALUE_ERROR); // TODO: Should fail, but doesn't because 10e parses to a string
7501+  assertFormulaEquals('="+$10.00" + 0', 10);
7502+  assertFormulaEquals('="-$10.00" + 0', -10);
7503+  assertFormulaEquals('="$+10.00" + 0', 10);
7504+  assertFormulaEquals('="$-10.00" + 0', -10);
7505 });
7506 
7507diff --git a/tsconfig.json b/tsconfig.json
7508index 1ba5ad0..9f9c924 100644
7509--- a/tsconfig.json
7510+++ b/tsconfig.json
7511@@ -3,9 +3,9 @@
7512     "allowJs": true,
7513     "allowUnreachableCode": true,
7514     "allowUnusedLabels": true,
7515-    "outDir": "output"
7516+    "outDir": "dist"
7517   },
7518   "files": [
7519-    "src/Main.ts"
7520+    "src/Sheet.ts"
7521   ]
7522 }