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 }