spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
ts.html and ts/sheet.ts working
author
Ben Vogt <[email protected]>
date
2016-12-26 18:06:42
stats
7 file(s) changed, 2348 insertions(+), 15 deletions(-)
files
js/TSParser.d.ts
js/sheet.ts
ts.html
ts/parser.js
ts/sheet.js
ts/sheet.ts
tsconfig.json
   1diff --git a/js/TSParser.d.ts b/js/TSParser.d.ts
   2deleted file mode 100644
   3index ebf4c90..0000000
   4--- a/js/TSParser.d.ts
   5+++ /dev/null
   6@@ -1,12 +0,0 @@
   7-interface P {
   8-  yy: any;
   9-  lexer: any;
  10-  parse: any;
  11-  parseError: any;
  12-}
  13-
  14-declare var Parser: P;
  15-
  16-export {
  17-  Parser
  18-}
  19\ No newline at end of file
  20diff --git a/js/sheet.ts b/js/sheet.ts
  21deleted file mode 100644
  22index 2791be5..0000000
  23--- a/js/sheet.ts
  24+++ /dev/null
  25@@ -1,3 +0,0 @@
  26-import * as Formula from "../lib/formulajs"
  27-/// <reference path="TSParser.d.ts"/>
  28-import { Parser } from "./TSParser";
  29diff --git a/ts.html b/ts.html
  30new file mode 100644
  31index 0000000..8a4b80b
  32--- /dev/null
  33+++ b/ts.html
  34@@ -0,0 +1,158 @@
  35+<!doctype html>
  36+<html>
  37+<head>
  38+  <meta charset='utf-8'>
  39+  <title>RuleJS - Like excel library to parse formulas.</title>
  40+
  41+  <!-- Latest compiled and minified CSS -->
  42+  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
  43+
  44+  <script src="lib/lodash/lodash.js"></script>
  45+  <script src="lib/underscore.string/underscore.string.js"></script>
  46+  <script src="lib/moment/moment.js"></script>
  47+  <script src="lib/numeral/numeral.js"></script>
  48+  <script src="lib/numericjs/numeric.js"></script>
  49+  <script src="lib/js-md5/md5.js"></script>
  50+  <script src="lib/jstat/jstat.js"></script>
  51+  <script src="lib/formulajs/formula.js"></script>
  52+
  53+  <script src="ts/parser.js"></script>
  54+  <script src="ts/sheet.js"></script>
  55+  <style>
  56+    .table input[type=text] {
  57+      width: 50px;
  58+    }
  59+    #suportedList ul {
  60+      -webkit-column-count: 4; -webkit-column-gap:20px;
  61+      -moz-column-count:4; -moz-column-gap:20px;
  62+      -o-column-count:4; -o-column-gap:20px;
  63+      column-count:4; column-gap:20px;
  64+    }
  65+  </style>
  66+</head>
  67+<body>
  68+<div class="col-xs-12">
  69+  <section>
  70+    <h1 class="page-header">RuleJS</h1>
  71+    <section>
  72+      <h1 class="page-header">Demo</h1>
  73+      <p>Try to parse the formula by typing ex. <code>AND(1,0)</code> into input below and press <kbd>Parse</kbd> button.</p>
  74+
  75+      <div class="col-xs-12" style="padding: 0px;" id="mine">
  76+
  77+        <input type="text" id="X1" placeholder="ex. AND(1,0)"><button>Parse</button>
  78+
  79+        <p class="bg-info" style="display: none">result: <span id="result"></span></p>
  80+        <p class="bg-danger" style="display: none">error: <span id="error"></span></p>
  81+        <p class="clearfix"></p>
  82+
  83+        <p>Try to insert formula into input field by typing ex. <code>=A1</code>. It's possible to edit formula by double clicked on input field.</p>
  84+        <table class="table table-bordered">
  85+          <thead>
  86+          <tr>
  87+            <td></td>
  88+            <td>A</td>
  89+            <td>B</td>
  90+            <td>C</td>
  91+            <td>D</td>
  92+            <td>E</td>
  93+            <td>F</td>
  94+            <td>G</td>
  95+            <td>H</td>
  96+            <td>I</td>
  97+            <td>J</td>
  98+            <td colspan="2" class="text-center">fn(x)</td>
  99+          </tr>
 100+          </thead>
 101+          <tbody>
 102+          <tr>
 103+            <td>1</td>
 104+            <td><input type="text" id="A1" value="1"></td>
 105+            <td><input type="text" id="B1" value="2"></td>
 106+            <td><input type="text" id="C1" value="3"></td>
 107+            <td><input type="text" id="D1" value="4"></td>
 108+            <td><input type="text" id="E1" value="5"></td>
 109+            <td><input type="text" id="F1" value="6"></td>
 110+            <td><input type="text" id="G1" value="7"></td>
 111+            <td><input type="text" id="H1" value="8"></td>
 112+            <td><input type="text" id="I1" value="9"></td>
 113+            <td><input type="text" id="J1" value="10"></td>
 114+            <td>SUM(A1:D1, H1)</td>
 115+            <td><span id="K1" data-formula="SUM(A1:D1, H1)"></span></td>
 116+          </tr>
 117+          <tr>
 118+            <td>2</td>
 119+            <td><input type="text" id="A2" value="-1"></td>
 120+            <td><input type="text" id="B2" value="-10"></td>
 121+            <td><input type="text" id="C2" value="2"></td>
 122+            <td><input type="text" id="D2" value="4"></td>
 123+            <td><input type="text" id="E2" value="100"></td>
 124+            <td><input type="text" id="F2" value="1"></td>
 125+            <td><input type="text" id="G2" value="50"></td>
 126+            <td><input type="text" id="H2" value="20"></td>
 127+            <td><input type="text" id="I2" value="200"></td>
 128+            <td><input type="text" id="J2" value="-100"></td>
 129+            <td>MAX(A2:J2)</td>
 130+            <td><span id="K2" data-formula="MAX(A2:J2)"></span></td>
 131+          </tr>
 132+          <tr>
 133+            <td>3</td>
 134+            <td><input type="text" id="A3" value="-1"></td>
 135+            <td><input type="text" id="B3" value="-40"></td>
 136+            <td><input type="text" id="C3" value="-53"></td>
 137+            <td><input type="text" id="D3" value="1"></td>
 138+            <td><input type="text" id="E3" value="10"></td>
 139+            <td><input type="text" id="F3" value="30"></td>
 140+            <td><input type="text" id="G3" value="10"></td>
 141+            <td><input type="text" id="H3" value="301"></td>
 142+            <td><input type="text" id="I3" value="-1"></td>
 143+            <td><input type="text" id="J3" value="-20"></td>
 144+            <td>MIN(A3:J3)</td>
 145+            <td><span id="K3" data-formula="MIN(A3:J3)"></span></td>
 146+          </tr>
 147+          <tr>
 148+            <td>4</td>
 149+            <td><input type="text" id="A4" value="20"></td>
 150+            <td><input type="text" id="B4" value="50"></td>
 151+            <td><input type="text" id="C4" value="100"></td>
 152+            <td><input type="text" id="D4" value="20"></td>
 153+            <td><input type="text" id="E4" value="1"></td>
 154+            <td><input type="text" id="F4" value="5"></td>
 155+            <td><input type="text" id="G4" value="15"></td>
 156+            <td><input type="text" id="H4" value="25"></td>
 157+            <td><input type="text" id="I4" value="45"></td>
 158+            <td><input type="text" id="J4" value="23"></td>
 159+            <td>AVERAGE(A4:J4):</td>
 160+            <td><span id="K4" data-formula="AVERAGE(A4:J4)"></span></td>
 161+          </tr>
 162+          <tr>
 163+            <td>5</td>
 164+            <td><input type="text" id="A5" value="0"></td>
 165+            <td><input type="text" id="B5" value="10"></td>
 166+            <td><input type="text" id="C5" value="1"></td>
 167+            <td><input type="text" id="D5" value="10"></td>
 168+            <td><input type="text" id="E5" value="2"></td>
 169+            <td><input type="text" id="F5" value="10"></td>
 170+            <td><input type="text" id="G5" value="3"></td>
 171+            <td><input type="text" id="H5" value="10"></td>
 172+            <td><input type="text" id="I5" value="4"></td>
 173+            <td><input type="text" id="J5" value="10"></td>
 174+            <td>SUMIF(A5:J5,'>5')</td>
 175+            <td><span id="K5" data-formula="SUMIF(A5:J5,'>5')"></span></td>
 176+          </tr>
 177+          </tbody>
 178+        </table>
 179+      </div>
 180+
 181+
 182+
 183+    </section>
 184+  </section>
 185+</div>
 186+
 187+<script>
 188+  var m = new mine('mine');
 189+  m.init();
 190+</script>
 191+</body>
 192+</html>
 193diff --git a/ts/parser.js b/ts/parser.js
 194new file mode 100644
 195index 0000000..f1f27a2
 196--- /dev/null
 197+++ b/ts/parser.js
 198@@ -0,0 +1,965 @@
 199+/* parser generated by jison 0.4.15 */
 200+/*
 201+ Returns a Parser object of the following structure:
 202+
 203+ Parser: {
 204+ yy: {}
 205+ }
 206+
 207+ Parser.prototype: {
 208+ yy: {},
 209+ trace: function(),
 210+ symbols_: {associative list: name ==> number},
 211+ terminals_: {associative list: number ==> name},
 212+ productions_: [...],
 213+ performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
 214+ table: [...],
 215+ defaultActions: {...},
 216+ parseError: function(str, hash),
 217+ parse: function(input),
 218+
 219+ lexer: {
 220+ EOF: 1,
 221+ parseError: function(str, hash),
 222+ setInput: function(input),
 223+ input: function(),
 224+ unput: function(str),
 225+ more: function(),
 226+ less: function(n),
 227+ pastInput: function(),
 228+ upcomingInput: function(),
 229+ showPosition: function(),
 230+ test_match: function(regex_match_array, rule_index),
 231+ next: function(),
 232+ lex: function(),
 233+ begin: function(condition),
 234+ popState: function(),
 235+ _currentRules: function(),
 236+ topState: function(),
 237+ pushState: function(condition),
 238+
 239+ options: {
 240+ ranges: boolean           (optional: true ==> token location info will include a .range[] member)
 241+ flex: boolean             (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
 242+ 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)
 243+ },
 244+
 245+ performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
 246+ rules: [...],
 247+ conditions: {associative list: name ==> set},
 248+ }
 249+ }
 250+
 251+
 252+ token location info (@$, _$, etc.): {
 253+ first_line: n,
 254+ last_line: n,
 255+ first_column: n,
 256+ last_column: n,
 257+ range: [start_number, end_number]       (where the numbers are indexes into the input string, regular zero-based)
 258+ }
 259+
 260+
 261+ the parseError function receives a 'hash' object with these members for lexer and parser errors: {
 262+ text:        (matched text)
 263+ token:       (the produced terminal token, if any)
 264+ line:        (yylineno)
 265+ }
 266+ while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
 267+ loc:         (yylloc)
 268+ expected:    (string describing the set of expected tokens)
 269+ recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
 270+ }
 271+ */
 272+var Parser = (function(){
 273+  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];
 274+  var parser = {trace: function trace() { },
 275+    yy: {},
 276+    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},
 277+    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:"!"},
 278+    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]],
 279+    performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
 280+      /* this == yyval */
 281+
 282+      var $0 = $$.length - 1;
 283+      switch (yystate) {
 284+        case 1:
 285+
 286+          return $$[$0-1];
 287+
 288+          break;
 289+        case 2:
 290+
 291+          this.$ = yy.handler.helper.callVariable.call(this, $$[$0]);
 292+
 293+          break;
 294+        case 3:
 295+
 296+          this.$ = yy.handler.time.call(yy.obj, $$[$0], true);
 297+
 298+          break;
 299+        case 4:
 300+
 301+          this.$ = yy.handler.time.call(yy.obj, $$[$0]);
 302+
 303+          break;
 304+        case 5:
 305+
 306+          this.$ = yy.handler.helper.number($$[$0]);
 307+
 308+          break;
 309+        case 6:
 310+
 311+          this.$ = yy.handler.helper.string($$[$0]);
 312+
 313+          break;
 314+        case 7:
 315+
 316+          this.$ = yy.handler.helper.specialMatch('&', $$[$0-2], $$[$0]);
 317+
 318+          break;
 319+        case 8:
 320+
 321+          this.$ = yy.handler.helper.logicMatch('=', $$[$0-2], $$[$0]);
 322+
 323+          break;
 324+        case 9:
 325+
 326+          this.$ = yy.handler.helper.mathMatch('+', $$[$0-2], $$[$0]);
 327+
 328+          break;
 329+        case 10:
 330+
 331+          this.$ = yy.handler.helper.number($$[$0-1]);
 332+
 333+          break;
 334+        case 11:
 335+
 336+          this.$ = yy.handler.helper.logicMatch('<=', $$[$0-3], $$[$0]);
 337+
 338+          break;
 339+        case 12:
 340+
 341+          this.$ = yy.handler.helper.logicMatch('>=', $$[$0-3], $$[$0]);
 342+
 343+          break;
 344+        case 13:
 345+
 346+          this.$ = yy.handler.helper.logicMatch('<>', $$[$0-3], $$[$0]);
 347+
 348+          break;
 349+        case 14:
 350+
 351+          this.$ = yy.handler.helper.logicMatch('NOT', $$[$0-2], $$[$0]);
 352+
 353+          break;
 354+        case 15:
 355+
 356+          this.$ = yy.handler.helper.logicMatch('>', $$[$0-2], $$[$0]);
 357+
 358+          break;
 359+        case 16:
 360+
 361+          this.$ = yy.handler.helper.logicMatch('<', $$[$0-2], $$[$0]);
 362+
 363+          break;
 364+        case 17:
 365+
 366+          this.$ = yy.handler.helper.mathMatch('-', $$[$0-2], $$[$0]);
 367+
 368+          break;
 369+        case 18:
 370+
 371+          this.$ = yy.handler.helper.mathMatch('*', $$[$0-2], $$[$0]);
 372+
 373+          break;
 374+        case 19:
 375+
 376+          this.$ = yy.handler.helper.mathMatch('/', $$[$0-2], $$[$0]);
 377+
 378+          break;
 379+        case 20:
 380+
 381+          this.$ = yy.handler.helper.mathMatch('^', $$[$0-2], $$[$0]);
 382+
 383+          break;
 384+        case 21:
 385+
 386+          var n1 = yy.handler.helper.numberInverted($$[$0]);
 387+          this.$ = n1;
 388+          if (isNaN(this.$)) {
 389+            this.$ = 0;
 390+          }
 391+
 392+          break;
 393+        case 22:
 394+
 395+          var n1 = yy.handler.helper.number($$[$0]);
 396+          this.$ = n1;
 397+          if (isNaN(this.$)) {
 398+            this.$ = 0;
 399+          }
 400+
 401+          break;
 402+        case 23:
 403+
 404+          this.$ = yy.handler.helper.callFunction.call(this, $$[$0-2], '');
 405+
 406+          break;
 407+        case 24:
 408+
 409+          this.$ = yy.handler.helper.callFunction.call(this, $$[$0-3], $$[$0-1]);
 410+
 411+          break;
 412+        case 28:
 413+
 414+          this.$ = yy.handler.helper.fixedCellValue.call(yy.obj, $$[$0]);
 415+
 416+          break;
 417+        case 29:
 418+
 419+          this.$ = yy.handler.helper.fixedCellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
 420+
 421+          break;
 422+        case 30:
 423+
 424+          this.$ = yy.handler.helper.cellValue.call(yy.obj, $$[$0]);
 425+
 426+          break;
 427+        case 31:
 428+
 429+          this.$ = yy.handler.helper.cellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
 430+
 431+          break;
 432+        case 32:
 433+
 434+          if (yy.handler.utils.isArray($$[$0])) {
 435+            this.$ = $$[$0];
 436+          } else {
 437+            this.$ = [$$[$0]];
 438+          }
 439+
 440+          break;
 441+        case 33:
 442+
 443+          var result = [],
 444+            arr = eval("[" + yytext + "]");
 445+
 446+          arr.forEach(function (item) {
 447+            result.push(item);
 448+          });
 449+
 450+          this.$ = result;
 451+
 452+          break;
 453+        case 34: case 35:
 454+
 455+        $$[$0-2].push($$[$0]);
 456+        this.$ = $$[$0-2];
 457+
 458+        break;
 459+        case 36:
 460+
 461+          this.$ = [$$[$0]];
 462+
 463+          break;
 464+        case 37:
 465+
 466+          this.$ = (yy.handler.utils.isArray($$[$0-2]) ? $$[$0-2] : [$$[$0-2]]);
 467+          this.$.push($$[$0]);
 468+
 469+          break;
 470+        case 38:
 471+
 472+          this.$ = $$[$0];
 473+
 474+          break;
 475+        case 39:
 476+
 477+          this.$ = ($$[$0-2] + '.' + $$[$0]) * 1;
 478+
 479+          break;
 480+        case 40:
 481+
 482+          this.$ = $$[$0-1] * 0.01;
 483+
 484+          break;
 485+        case 41: case 42:
 486+
 487+        this.$ = $$[$0-2] + $$[$0-1] + $$[$0];
 488+
 489+        break;
 490+      }
 491+    },
 492+    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})],
 493+    defaultActions: {19:[2,1]},
 494+    parseError: function parseError(str, hash) {
 495+      if (hash.recoverable) {
 496+        this.trace(str);
 497+      } else {
 498+        throw new Error(str);
 499+      }
 500+    },
 501+    parse: function parse(input) {
 502+      var self = this,
 503+        stack = [0],
 504+        tstack = [], // token stack
 505+        vstack = [null], // semantic value stack
 506+        lstack = [], // location stack
 507+        table = this.table,
 508+        yytext = '',
 509+        yylineno = 0,
 510+        yyleng = 0,
 511+        recovering = 0,
 512+        TERROR = 2,
 513+        EOF = 1;
 514+
 515+      var args = lstack.slice.call(arguments, 1);
 516+
 517+      //this.reductionCount = this.shiftCount = 0;
 518+
 519+      var lexer = Object.create(this.lexer);
 520+      var sharedState = { yy: {} };
 521+      // copy state
 522+      for (var k in this.yy) {
 523+        if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
 524+          sharedState.yy[k] = this.yy[k];
 525+        }
 526+      }
 527+
 528+      lexer.setInput(input, sharedState.yy);
 529+      sharedState.yy.lexer = lexer;
 530+      sharedState.yy.parser = this;
 531+      if (typeof lexer.yylloc == 'undefined') {
 532+        lexer.yylloc = {};
 533+      }
 534+      var yyloc = lexer.yylloc;
 535+      lstack.push(yyloc);
 536+
 537+      var ranges = lexer.options && lexer.options.ranges;
 538+
 539+      if (typeof sharedState.yy.parseError === 'function') {
 540+        this.parseError = sharedState.yy.parseError;
 541+      } else {
 542+        this.parseError = Object.getPrototypeOf(this).parseError;
 543+      }
 544+
 545+      function popStack (n) {
 546+        stack.length = stack.length - 2 * n;
 547+        vstack.length = vstack.length - n;
 548+        lstack.length = lstack.length - n;
 549+      }
 550+
 551+      _token_stack:
 552+        function lex() {
 553+          var token;
 554+          token = lexer.lex() || EOF;
 555+          // if token isn't its numeric value, convert
 556+          if (typeof token !== 'number') {
 557+            token = self.symbols_[token] || token;
 558+          }
 559+          return token;
 560+        }
 561+
 562+      var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
 563+      while (true) {
 564+        // retreive state number from top of stack
 565+        state = stack[stack.length - 1];
 566+
 567+        // use default actions if available
 568+        if (this.defaultActions[state]) {
 569+          action = this.defaultActions[state];
 570+        } else {
 571+          if (symbol === null || typeof symbol == 'undefined') {
 572+            symbol = lex();
 573+          }
 574+          // read action for current state and first input
 575+          action = table[state] && table[state][symbol];
 576+        }
 577+
 578+        _handle_error:
 579+          // handle parse error
 580+          if (typeof action === 'undefined' || !action.length || !action[0]) {
 581+            var error_rule_depth;
 582+            var errStr = '';
 583+
 584+            // Return the rule stack depth where the nearest error rule can be found.
 585+            // Return FALSE when no error recovery rule was found.
 586+            function locateNearestErrorRecoveryRule(state) {
 587+              var stack_probe = stack.length - 1;
 588+              var depth = 0;
 589+
 590+              // try to recover from error
 591+              for(;;) {
 592+                // check for error recovery rule in this state
 593+                if ((TERROR.toString()) in table[state]) {
 594+                  return depth;
 595+                }
 596+                if (state === 0 || stack_probe < 2) {
 597+                  return false; // No suitable error recovery rule available.
 598+                }
 599+                stack_probe -= 2; // popStack(1): [symbol, action]
 600+                state = stack[stack_probe];
 601+                ++depth;
 602+              }
 603+            }
 604+
 605+            if (!recovering) {
 606+              // first see if there's any chance at hitting an error recovery rule:
 607+              error_rule_depth = locateNearestErrorRecoveryRule(state);
 608+
 609+              // Report error
 610+              expected = [];
 611+              for (p in table[state]) {
 612+                if (this.terminals_[p] && p > TERROR) {
 613+                  expected.push("'"+this.terminals_[p]+"'");
 614+                }
 615+              }
 616+              if (lexer.showPosition) {
 617+                errStr = 'Parse error on line '+(yylineno+1)+":\n"+lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + (this.terminals_[symbol] || symbol)+ "'";
 618+              } else {
 619+                errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
 620+                  (symbol == EOF ? "end of input" :
 621+                    ("'"+(this.terminals_[symbol] || symbol)+"'"));
 622+              }
 623+              this.parseError(errStr, {
 624+                text: lexer.match,
 625+                token: this.terminals_[symbol] || symbol,
 626+                line: lexer.yylineno,
 627+                loc: yyloc,
 628+                expected: expected,
 629+                recoverable: (error_rule_depth !== false)
 630+              });
 631+            } else if (preErrorSymbol !== EOF) {
 632+              error_rule_depth = locateNearestErrorRecoveryRule(state);
 633+            }
 634+
 635+            // just recovered from another error
 636+            if (recovering == 3) {
 637+              if (symbol === EOF || preErrorSymbol === EOF) {
 638+                throw new Error(errStr || 'Parsing halted while starting to recover from another error.');
 639+              }
 640+
 641+              // discard current lookahead and grab another
 642+              yyleng = lexer.yyleng;
 643+              yytext = lexer.yytext;
 644+              yylineno = lexer.yylineno;
 645+              yyloc = lexer.yylloc;
 646+              symbol = lex();
 647+            }
 648+
 649+            // try to recover from error
 650+            if (error_rule_depth === false) {
 651+              throw new Error(errStr || 'Parsing halted. No suitable error recovery rule available.');
 652+            }
 653+            popStack(error_rule_depth);
 654+
 655+            preErrorSymbol = (symbol == TERROR ? null : symbol); // save the lookahead token
 656+            symbol = TERROR;         // insert generic error symbol as new lookahead
 657+            state = stack[stack.length-1];
 658+            action = table[state] && table[state][TERROR];
 659+            recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
 660+          }
 661+
 662+        // this shouldn't happen, unless resolve defaults are off
 663+        if (action[0] instanceof Array && action.length > 1) {
 664+          throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
 665+        }
 666+
 667+        switch (action[0]) {
 668+          case 1: // shift
 669+            //this.shiftCount++;
 670+
 671+            stack.push(symbol);
 672+            vstack.push(lexer.yytext);
 673+            lstack.push(lexer.yylloc);
 674+            stack.push(action[1]); // push state
 675+            symbol = null;
 676+            if (!preErrorSymbol) { // normal execution/no error
 677+              yyleng = lexer.yyleng;
 678+              yytext = lexer.yytext;
 679+              yylineno = lexer.yylineno;
 680+              yyloc = lexer.yylloc;
 681+              if (recovering > 0) {
 682+                recovering--;
 683+              }
 684+            } else {
 685+              // error just occurred, resume old lookahead f/ before error
 686+              symbol = preErrorSymbol;
 687+              preErrorSymbol = null;
 688+            }
 689+            break;
 690+
 691+          case 2:
 692+            // reduce
 693+            //this.reductionCount++;
 694+
 695+            len = this.productions_[action[1]][1];
 696+
 697+            // perform semantic action
 698+            yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
 699+            // default location, uses first token for firsts, last for lasts
 700+            yyval._$ = {
 701+              first_line: lstack[lstack.length-(len||1)].first_line,
 702+              last_line: lstack[lstack.length-1].last_line,
 703+              first_column: lstack[lstack.length-(len||1)].first_column,
 704+              last_column: lstack[lstack.length-1].last_column
 705+            };
 706+            if (ranges) {
 707+              yyval._$.range = [lstack[lstack.length-(len||1)].range[0], lstack[lstack.length-1].range[1]];
 708+            }
 709+            r = this.performAction.apply(yyval, [yytext, yyleng, yylineno, sharedState.yy, action[1], vstack, lstack].concat(args));
 710+
 711+            if (typeof r !== 'undefined') {
 712+              return r;
 713+            }
 714+
 715+            // pop off stack
 716+            if (len) {
 717+              stack = stack.slice(0,-1*len*2);
 718+              vstack = vstack.slice(0, -1*len);
 719+              lstack = lstack.slice(0, -1*len);
 720+            }
 721+
 722+            stack.push(this.productions_[action[1]][0]);    // push nonterminal (reduce)
 723+            vstack.push(yyval.$);
 724+            lstack.push(yyval._$);
 725+            // goto new state = table[STATE][NONTERMINAL]
 726+            newState = table[stack[stack.length-2]][stack[stack.length-1]];
 727+            stack.push(newState);
 728+            break;
 729+
 730+          case 3:
 731+            // accept
 732+            return true;
 733+        }
 734+
 735+      }
 736+
 737+      return true;
 738+    }};
 739+
 740+  /* generated by jison-lex 0.3.4 */
 741+  var lexer = (function(){
 742+    var lexer = ({
 743+
 744+      EOF:1,
 745+
 746+      parseError:function parseError(str, hash) {
 747+        if (this.yy.parser) {
 748+          this.yy.parser.parseError(str, hash);
 749+        } else {
 750+          throw new Error(str);
 751+        }
 752+      },
 753+
 754+// resets the lexer, sets new input
 755+      setInput:function (input, yy) {
 756+        this.yy = yy || this.yy || {};
 757+        this._input = input;
 758+        this._more = this._backtrack = this.done = false;
 759+        this.yylineno = this.yyleng = 0;
 760+        this.yytext = this.matched = this.match = '';
 761+        this.conditionStack = ['INITIAL'];
 762+        this.yylloc = {
 763+          first_line: 1,
 764+          first_column: 0,
 765+          last_line: 1,
 766+          last_column: 0
 767+        };
 768+        if (this.options.ranges) {
 769+          this.yylloc.range = [0,0];
 770+        }
 771+        this.offset = 0;
 772+        return this;
 773+      },
 774+
 775+// consumes and returns one char from the input
 776+      input:function () {
 777+        var ch = this._input[0];
 778+        this.yytext += ch;
 779+        this.yyleng++;
 780+        this.offset++;
 781+        this.match += ch;
 782+        this.matched += ch;
 783+        var lines = ch.match(/(?:\r\n?|\n).*/g);
 784+        if (lines) {
 785+          this.yylineno++;
 786+          this.yylloc.last_line++;
 787+        } else {
 788+          this.yylloc.last_column++;
 789+        }
 790+        if (this.options.ranges) {
 791+          this.yylloc.range[1]++;
 792+        }
 793+
 794+        this._input = this._input.slice(1);
 795+        return ch;
 796+      },
 797+
 798+// unshifts one char (or a string) into the input
 799+      unput:function (ch) {
 800+        var len = ch.length;
 801+        var lines = ch.split(/(?:\r\n?|\n)/g);
 802+
 803+        this._input = ch + this._input;
 804+        this.yytext = this.yytext.substr(0, this.yytext.length - len);
 805+        //this.yyleng -= len;
 806+        this.offset -= len;
 807+        var oldLines = this.match.split(/(?:\r\n?|\n)/g);
 808+        this.match = this.match.substr(0, this.match.length - 1);
 809+        this.matched = this.matched.substr(0, this.matched.length - 1);
 810+
 811+        if (lines.length - 1) {
 812+          this.yylineno -= lines.length - 1;
 813+        }
 814+        var r = this.yylloc.range;
 815+
 816+        this.yylloc = {
 817+          first_line: this.yylloc.first_line,
 818+          last_line: this.yylineno + 1,
 819+          first_column: this.yylloc.first_column,
 820+          last_column: lines ?
 821+          (lines.length === oldLines.length ? this.yylloc.first_column : 0)
 822+          + oldLines[oldLines.length - lines.length].length - lines[0].length :
 823+          this.yylloc.first_column - len
 824+        };
 825+
 826+        if (this.options.ranges) {
 827+          this.yylloc.range = [r[0], r[0] + this.yyleng - len];
 828+        }
 829+        this.yyleng = this.yytext.length;
 830+        return this;
 831+      },
 832+
 833+// When called from action, caches matched text and appends it on next action
 834+      more:function () {
 835+        this._more = true;
 836+        return this;
 837+      },
 838+
 839+// 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.
 840+      reject:function () {
 841+        if (this.options.backtrack_lexer) {
 842+          this._backtrack = true;
 843+        } else {
 844+          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(), {
 845+            text: "",
 846+            token: null,
 847+            line: this.yylineno
 848+          });
 849+
 850+        }
 851+        return this;
 852+      },
 853+
 854+// retain first n characters of the match
 855+      less:function (n) {
 856+        this.unput(this.match.slice(n));
 857+      },
 858+
 859+// displays already matched input, i.e. for error messages
 860+      pastInput:function () {
 861+        var past = this.matched.substr(0, this.matched.length - this.match.length);
 862+        return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
 863+      },
 864+
 865+// displays upcoming input, i.e. for error messages
 866+      upcomingInput:function () {
 867+        var next = this.match;
 868+        if (next.length < 20) {
 869+          next += this._input.substr(0, 20-next.length);
 870+        }
 871+        return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
 872+      },
 873+
 874+// displays the character position where the lexing error occurred, i.e. for error messages
 875+      showPosition:function () {
 876+        var pre = this.pastInput();
 877+        var c = new Array(pre.length + 1).join("-");
 878+        return pre + this.upcomingInput() + "\n" + c + "^";
 879+      },
 880+
 881+// test the lexed token: return FALSE when not a match, otherwise return token
 882+      test_match:function (match, indexed_rule) {
 883+        var token,
 884+          lines,
 885+          backup;
 886+
 887+        if (this.options.backtrack_lexer) {
 888+          // save context
 889+          backup = {
 890+            yylineno: this.yylineno,
 891+            yylloc: {
 892+              first_line: this.yylloc.first_line,
 893+              last_line: this.last_line,
 894+              first_column: this.yylloc.first_column,
 895+              last_column: this.yylloc.last_column
 896+            },
 897+            yytext: this.yytext,
 898+            match: this.match,
 899+            matches: this.matches,
 900+            matched: this.matched,
 901+            yyleng: this.yyleng,
 902+            offset: this.offset,
 903+            _more: this._more,
 904+            _input: this._input,
 905+            yy: this.yy,
 906+            conditionStack: this.conditionStack.slice(0),
 907+            done: this.done
 908+          };
 909+          if (this.options.ranges) {
 910+            backup.yylloc.range = this.yylloc.range.slice(0);
 911+          }
 912+        }
 913+
 914+        lines = match[0].match(/(?:\r\n?|\n).*/g);
 915+        if (lines) {
 916+          this.yylineno += lines.length;
 917+        }
 918+        this.yylloc = {
 919+          first_line: this.yylloc.last_line,
 920+          last_line: this.yylineno + 1,
 921+          first_column: this.yylloc.last_column,
 922+          last_column: lines ?
 923+          lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
 924+          this.yylloc.last_column + match[0].length
 925+        };
 926+        this.yytext += match[0];
 927+        this.match += match[0];
 928+        this.matches = match;
 929+        this.yyleng = this.yytext.length;
 930+        if (this.options.ranges) {
 931+          this.yylloc.range = [this.offset, this.offset += this.yyleng];
 932+        }
 933+        this._more = false;
 934+        this._backtrack = false;
 935+        this._input = this._input.slice(match[0].length);
 936+        this.matched += match[0];
 937+        token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
 938+        if (this.done && this._input) {
 939+          this.done = false;
 940+        }
 941+        if (token) {
 942+          return token;
 943+        } else if (this._backtrack) {
 944+          // recover context
 945+          for (var k in backup) {
 946+            this[k] = backup[k];
 947+          }
 948+          return false; // rule action called reject() implying the next rule should be tested instead.
 949+        }
 950+        return false;
 951+      },
 952+
 953+// return next match in input
 954+      next:function () {
 955+        if (this.done) {
 956+          return this.EOF;
 957+        }
 958+        if (!this._input) {
 959+          this.done = true;
 960+        }
 961+
 962+        var token,
 963+          match,
 964+          tempMatch,
 965+          index;
 966+        if (!this._more) {
 967+          this.yytext = '';
 968+          this.match = '';
 969+        }
 970+        var rules = this._currentRules();
 971+        for (var i = 0; i < rules.length; i++) {
 972+          tempMatch = this._input.match(this.rules[rules[i]]);
 973+          if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
 974+            match = tempMatch;
 975+            index = i;
 976+            if (this.options.backtrack_lexer) {
 977+              token = this.test_match(tempMatch, rules[i]);
 978+              if (token !== false) {
 979+                return token;
 980+              } else if (this._backtrack) {
 981+                match = false;
 982+                continue; // rule action called reject() implying a rule MISmatch.
 983+              } else {
 984+                // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
 985+                return false;
 986+              }
 987+            } else if (!this.options.flex) {
 988+              break;
 989+            }
 990+          }
 991+        }
 992+        if (match) {
 993+          token = this.test_match(match, rules[index]);
 994+          if (token !== false) {
 995+            return token;
 996+          }
 997+          // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
 998+          return false;
 999+        }
1000+        if (this._input === "") {
1001+          return this.EOF;
1002+        } else {
1003+          return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
1004+            text: "",
1005+            token: null,
1006+            line: this.yylineno
1007+          });
1008+        }
1009+      },
1010+
1011+// return next match that has a token
1012+      lex:function lex() {
1013+        var r = this.next();
1014+        if (r) {
1015+          return r;
1016+        } else {
1017+          return this.lex();
1018+        }
1019+      },
1020+
1021+// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
1022+      begin:function begin(condition) {
1023+        this.conditionStack.push(condition);
1024+      },
1025+
1026+// pop the previously active lexer condition state off the condition stack
1027+      popState:function popState() {
1028+        var n = this.conditionStack.length - 1;
1029+        if (n > 0) {
1030+          return this.conditionStack.pop();
1031+        } else {
1032+          return this.conditionStack[0];
1033+        }
1034+      },
1035+
1036+// produce the lexer rule set which is active for the currently active lexer condition state
1037+      _currentRules:function _currentRules() {
1038+        if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
1039+          return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
1040+        } else {
1041+          return this.conditions["INITIAL"].rules;
1042+        }
1043+      },
1044+
1045+// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
1046+      topState:function topState(n) {
1047+        n = this.conditionStack.length - 1 - Math.abs(n || 0);
1048+        if (n >= 0) {
1049+          return this.conditionStack[n];
1050+        } else {
1051+          return "INITIAL";
1052+        }
1053+      },
1054+
1055+// alias for begin(condition)
1056+      pushState:function pushState(condition) {
1057+        this.begin(condition);
1058+      },
1059+
1060+// return the number of states currently on the stack
1061+      stateStackSize:function stateStackSize() {
1062+        return this.conditionStack.length;
1063+      },
1064+      options: {},
1065+      performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
1066+        var YYSTATE=YY_START;
1067+        switch($avoiding_name_collisions) {
1068+          case 0:/* skip whitespace */
1069+            break;
1070+          case 1:return 10;
1071+            break;
1072+          case 2:return 10;
1073+            break;
1074+          case 3:return 23;
1075+            break;
1076+          case 4:return 7;
1077+            break;
1078+          case 5:return 8;
1079+            break;
1080+          case 6:
1081+            //if (yy.obj.type == 'cell') return 26;
1082+            //return 32;
1083+            return 26
1084+
1085+            break;
1086+          case 7:
1087+            //if (yy.obj.type == 'cell') return 28;
1088+            //return 32;
1089+            return 28;
1090+
1091+            break;
1092+          case 8:return 23;
1093+            break;
1094+          case 9:return 32;
1095+            break;
1096+          case 10:return 32;
1097+            break;
1098+          case 11:return 34;
1099+            break;
1100+          case 12:return 29;
1101+            break;
1102+          case 13:/* skip whitespace */
1103+            break;
1104+          case 14:return 11;
1105+            break;
1106+          case 15:return ' ';
1107+            break;
1108+          case 16:return 33;
1109+            break;
1110+          case 17:return 27;
1111+            break;
1112+          case 18:return 30;
1113+            break;
1114+          case 19:return 31;
1115+            break;
1116+          case 20:return 20;
1117+            break;
1118+          case 21:return 21;
1119+            break;
1120+          case 22:return 19;
1121+            break;
1122+          case 23:return 13;
1123+            break;
1124+          case 24:return 22;
1125+            break;
1126+          case 25:return 14;
1127+            break;
1128+          case 26:return 15;
1129+            break;
1130+          case 27:return 17;
1131+            break;
1132+          case 28:return 16;
1133+            break;
1134+          case 29:return 18;
1135+            break;
1136+          case 30:return '"';
1137+            break;
1138+          case 31:return "'";
1139+            break;
1140+          case 32:return "!";
1141+            break;
1142+          case 33:return 12;
1143+            break;
1144+          case 34:return 35;
1145+            break;
1146+          case 35:return 36;
1147+            break;
1148+          case 36:return 5;
1149+            break;
1150+        }
1151+      },
1152+      rules: [/^(?:\s+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:[A-Za-z]{1,}[A-Za-z_0-9]+(?=[(]))/,/^(?:([0]?[1-9]|1[0-2])[:][0-5][0-9]([:][0-5][0-9])?[ ]?(AM|am|aM|Am|PM|pm|pM|Pm))/,/^(?:([0]?[0-9]|1[0-9]|2[0-3])[:][0-5][0-9]([:][0-5][0-9])?)/,/^(?:\$[A-Za-z]+\$[0-9]+)/,/^(?:[A-Za-z]+[0-9]+)/,/^(?:[A-Za-z]+(?=[(]))/,/^(?:[A-Za-z]{1,}[A-Za-z_0-9]+)/,/^(?:[A-Za-z_]+)/,/^(?:[0-9]+)/,/^(?:\[(.*)?\])/,/^(?:\$)/,/^(?:&)/,/^(?: )/,/^(?:[.])/,/^(?::)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\/)/,/^(?:-)/,/^(?:\+)/,/^(?:\^)/,/^(?:\()/,/^(?:\))/,/^(?:>)/,/^(?:<)/,/^(?:NOT\b)/,/^(?:")/,/^(?:')/,/^(?:!)/,/^(?:=)/,/^(?:%)/,/^(?:[#])/,/^(?:$)/],
1153+      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}}
1154+    });
1155+    return lexer;
1156+  })();
1157+  parser.lexer = lexer;
1158+  function Parser () {
1159+    this.yy = {};
1160+  }
1161+  Parser.prototype = parser;parser.Parser = Parser;
1162+  return new Parser;
1163+})();
1164\ No newline at end of file
1165diff --git a/ts/sheet.js b/ts/sheet.js
1166new file mode 100644
1167index 0000000..d6e9408
1168--- /dev/null
1169+++ b/ts/sheet.js
1170@@ -0,0 +1,535 @@
1171+var mine = (function () {
1172+    'use strict';
1173+    var instance = this;
1174+    var parser = {
1175+        setObj: function (thing) {
1176+        },
1177+        parse: function (thing) {
1178+        }
1179+    };
1180+    var FormulaParser = function (handler) {
1181+        var formulaLexer = function () { };
1182+        formulaLexer.prototype = Parser.lexer;
1183+        var formulaParser = function () {
1184+            this.lexer = new formulaLexer();
1185+            this.yy = {};
1186+        };
1187+        formulaParser.prototype = Parser;
1188+        var newParser = new formulaParser;
1189+        newParser.setObj = function (obj) {
1190+            newParser.yy.obj = obj;
1191+        };
1192+        newParser.yy.parseError = function (str, hash) {
1193+            throw {
1194+                name: 'Parser error',
1195+                message: str,
1196+                prop: hash
1197+            };
1198+        };
1199+        newParser.yy.handler = handler;
1200+        return newParser;
1201+    };
1202+    var Exception = {
1203+        errors: [
1204+            { type: 'NULL', output: '#NULL' },
1205+            { type: 'DIV_ZERO', output: '#DIV/0!' },
1206+            { type: 'VALUE', output: '#VALUE!' },
1207+            { type: 'REF', output: '#REF!' },
1208+            { type: 'NAME', output: '#NAME?' },
1209+            { type: 'NUM', output: '#NUM!' },
1210+            { type: 'NOT_AVAILABLE', output: '#N/A!' },
1211+            { type: 'ERROR', output: '#ERROR' }
1212+        ],
1213+        get: function (type) {
1214+            var error = Exception.errors.filter(function (item) {
1215+                return item.type === type || item.output === type;
1216+            })[0];
1217+            return error ? error.output : null;
1218+        }
1219+    };
1220+    var Matrix = function () {
1221+        // var item = {
1222+        //   id: '',
1223+        //   formula: '',
1224+        //   value: '',
1225+        //   error: '',
1226+        //   deps: [],
1227+        //   formulaEdit: false
1228+        // };
1229+        this.data = [];
1230+        this.getItem = function (id) {
1231+            return instance.matrix.data.filter(function (item) {
1232+                return item.id === id;
1233+            })[0];
1234+        };
1235+        this.removeItem = function (id) {
1236+            instance.matrix.data = instance.matrix.data.filter(function (item) {
1237+                return item.id !== id;
1238+            });
1239+        };
1240+        this.updateItem = function (item, props) {
1241+            if (instance.utils.isString(item)) {
1242+                item = instance.matrix.getItem(item);
1243+            }
1244+            if (item && props) {
1245+                for (var p in props) {
1246+                    if (item[p] && instance.utils.isArray(item[p])) {
1247+                        if (instance.utils.isArray(props[p])) {
1248+                            props[p].forEach(function (i) {
1249+                                if (item[p].indexOf(i) === -1) {
1250+                                    item[p].push(i);
1251+                                }
1252+                            });
1253+                        }
1254+                        else {
1255+                            if (item[p].indexOf(props[p]) === -1) {
1256+                                item[p].push(props[p]);
1257+                            }
1258+                        }
1259+                    }
1260+                    else {
1261+                        item[p] = props[p];
1262+                    }
1263+                }
1264+            }
1265+        };
1266+        this.addItem = function (item) {
1267+            var cellId = item.id, coords = instance.utils.cellCoords(cellId);
1268+            item.row = coords.row;
1269+            item.col = coords.col;
1270+            var cellExist = instance.matrix.data.filter(function (cell) {
1271+                return cell.id === cellId;
1272+            })[0];
1273+            if (!cellExist) {
1274+                instance.matrix.data.push(item);
1275+            }
1276+            else {
1277+                instance.matrix.updateItem(cellExist, item);
1278+            }
1279+            return instance.matrix.getItem(cellId);
1280+        };
1281+        this.updateCellItem = function (id, props) {
1282+            var item = instance.matrix.getItem(id);
1283+            instance.matrix.updateItem(item, props);
1284+        };
1285+        this.getDependencies = function (id) {
1286+            var getDependencies = function (id) {
1287+                var filtered = instance.matrix.data.filter(function (cell) {
1288+                    if (cell.deps) {
1289+                        return cell.deps.indexOf(id) > -1;
1290+                    }
1291+                });
1292+                var deps = [];
1293+                filtered.forEach(function (cell) {
1294+                    if (deps.indexOf(cell.id) === -1) {
1295+                        deps.push(cell.id);
1296+                    }
1297+                });
1298+                return deps;
1299+            };
1300+            var allDependencies = [];
1301+            var getTotalDependencies = function (id) {
1302+                var deps = getDependencies(id);
1303+                if (deps.length) {
1304+                    deps.forEach(function (refId) {
1305+                        if (allDependencies.indexOf(refId) === -1) {
1306+                            allDependencies.push(refId);
1307+                            var item = instance.matrix.getItem(refId);
1308+                            if (item.deps.length) {
1309+                                getTotalDependencies(refId);
1310+                            }
1311+                        }
1312+                    });
1313+                }
1314+            };
1315+            getTotalDependencies(id);
1316+            return allDependencies;
1317+        };
1318+        this.getCellDependencies = function (cell) {
1319+            return instance.matrix.getDependencies(cell.id);
1320+        };
1321+        var recalculateCellDependencies = function (cell) {
1322+            var allDependencies = instance.matrix.getCellDependencies(cell);
1323+            allDependencies.forEach(function (refId) {
1324+                var currentCell = instance.matrix.getItem(refId);
1325+                if (currentCell && currentCell.formula) {
1326+                    calculateCellFormula(currentCell.formula, currentCell.id);
1327+                }
1328+            });
1329+        };
1330+        var calculateCellFormula = function (formula, id) {
1331+            // to avoid double translate formulas, update item data in parser
1332+            var parsed = parse(formula, id), value = parsed.result, error = parsed.error;
1333+            instance.matrix.updateCellItem(id, { value: value, error: error });
1334+            return parsed;
1335+        };
1336+        var registerCellInMatrix = function (cell) {
1337+            instance.matrix.addItem(cell);
1338+            calculateCellFormula(cell.formula, cell.id);
1339+        };
1340+        this.scan = function () {
1341+            var input = [
1342+                [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "SUM(A1:D1, H1)"],
1343+                [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "MAX(A2:J2)"],
1344+                [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "MIN(A3:J3)"],
1345+                [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "AVERAGE(A4:J4)"],
1346+                [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "SUMIF(A5:J5,'>5')"]
1347+            ];
1348+            for (var y = 0; y < input.length; y++) {
1349+                for (var x = 0; x < input[0].length; x++) {
1350+                    // set the cell here
1351+                    var id = utils.XYtoA1(x, y);
1352+                    var cell = {
1353+                        id: id,
1354+                        formula: input[y][x].toString()
1355+                    };
1356+                    registerCellInMatrix(cell);
1357+                    recalculateCellDependencies(cell);
1358+                }
1359+            }
1360+            console.log(this.data);
1361+        };
1362+    };
1363+    var utils = {
1364+        isArray: function (value) {
1365+            return Object.prototype.toString.call(value) === '[object Array]';
1366+        },
1367+        isNumber: function (value) {
1368+            return Object.prototype.toString.call(value) === '[object Number]';
1369+        },
1370+        isString: function (value) {
1371+            return Object.prototype.toString.call(value) === '[object String]';
1372+        },
1373+        isFunction: function (value) {
1374+            return Object.prototype.toString.call(value) === '[object Function]';
1375+        },
1376+        isUndefined: function (value) {
1377+            return Object.prototype.toString.call(value) === '[object Undefined]';
1378+        },
1379+        isNull: function (value) {
1380+            return Object.prototype.toString.call(value) === '[object Null]';
1381+        },
1382+        isSet: function (value) {
1383+            return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
1384+        },
1385+        getCellAlphaNum: function (cell) {
1386+            var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
1387+            return {
1388+                alpha: alpha,
1389+                num: parseInt(num[0], 10)
1390+            };
1391+        },
1392+        toNum: function (chr) {
1393+            chr = instance.utils.clearFormula(chr);
1394+            var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
1395+            for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
1396+                result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
1397+            }
1398+            if (result) {
1399+                --result;
1400+            }
1401+            return result;
1402+        },
1403+        toChar: function (num) {
1404+            var s = '';
1405+            while (num >= 0) {
1406+                s = String.fromCharCode(num % 26 + 97) + s;
1407+                num = Math.floor(num / 26) - 1;
1408+            }
1409+            return s.toUpperCase();
1410+        },
1411+        XYtoA1: function (x, y) {
1412+            function numberToLetters(num) {
1413+                var mod = num % 26, pow = num / 26 | 0, out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
1414+                return pow ? numberToLetters(pow) + out : out;
1415+            }
1416+            return numberToLetters(x + 1) + (y + 1).toString();
1417+        },
1418+        cellCoords: function (cell) {
1419+            var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
1420+            return {
1421+                row: parseInt(num[0], 10) - 1,
1422+                col: instance.utils.toNum(alpha)
1423+            };
1424+        },
1425+        clearFormula: function (formula) {
1426+            return formula.replace(/\$/g, '');
1427+        },
1428+        translateCellCoords: function (coords) {
1429+            return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
1430+        },
1431+        iterateCells: function (startCell, endCell, callback) {
1432+            var result = {
1433+                index: [],
1434+                value: [] // list of cell value
1435+            };
1436+            var cols = {
1437+                start: 0,
1438+                end: 0
1439+            };
1440+            if (endCell.col >= startCell.col) {
1441+                cols = {
1442+                    start: startCell.col,
1443+                    end: endCell.col
1444+                };
1445+            }
1446+            else {
1447+                cols = {
1448+                    start: endCell.col,
1449+                    end: startCell.col
1450+                };
1451+            }
1452+            var rows = {
1453+                start: 0,
1454+                end: 0
1455+            };
1456+            if (endCell.row >= startCell.row) {
1457+                rows = {
1458+                    start: startCell.row,
1459+                    end: endCell.row
1460+                };
1461+            }
1462+            else {
1463+                rows = {
1464+                    start: endCell.row,
1465+                    end: startCell.row
1466+                };
1467+            }
1468+            for (var column = cols.start; column <= cols.end; column++) {
1469+                for (var row = rows.start; row <= rows.end; row++) {
1470+                    var cellIndex = instance.utils.toChar(column) + (row + 1), cellValue = instance.helper.cellValue.call(this, cellIndex);
1471+                    result.index.push(cellIndex);
1472+                    result.value.push(cellValue);
1473+                }
1474+            }
1475+            if (instance.utils.isFunction(callback)) {
1476+                return callback.apply(callback, [result]);
1477+            }
1478+            else {
1479+                return result;
1480+            }
1481+        },
1482+        sort: function (rev) {
1483+            return function (a, b) {
1484+                return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
1485+            };
1486+        }
1487+    };
1488+    var helper = {
1489+        SUPPORTED_FORMULAS: [
1490+            'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
1491+            'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
1492+            'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
1493+            'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
1494+            'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
1495+            'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
1496+            'IF', 'INT', 'ISEVEN', 'ISODD',
1497+            'LN', 'LOG', 'LOG10',
1498+            'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
1499+            'NOT',
1500+            'ODD', 'OR',
1501+            'PI', 'POWER',
1502+            'ROUND', 'ROUNDDOWN', 'ROUNDUP',
1503+            'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
1504+            'TAN', 'TANH', 'TRUE', 'TRUNC',
1505+            'XOR'
1506+        ],
1507+        number: function (num) {
1508+            switch (typeof num) {
1509+                case 'number':
1510+                    return num;
1511+                case 'string':
1512+                    if (!isNaN(num)) {
1513+                        return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
1514+                    }
1515+            }
1516+            return num;
1517+        },
1518+        string: function (str) {
1519+            return str.substring(1, str.length - 1);
1520+        },
1521+        numberInverted: function (num) {
1522+            return this.number(num) * (-1);
1523+        },
1524+        specialMatch: function (type, exp1, exp2) {
1525+            var result;
1526+            switch (type) {
1527+                case '&':
1528+                    result = exp1.toString() + exp2.toString();
1529+                    break;
1530+            }
1531+            return result;
1532+        },
1533+        logicMatch: function (type, exp1, exp2) {
1534+            var result;
1535+            switch (type) {
1536+                case '=':
1537+                    result = (exp1 === exp2);
1538+                    break;
1539+                case '>':
1540+                    result = (exp1 > exp2);
1541+                    break;
1542+                case '<':
1543+                    result = (exp1 < exp2);
1544+                    break;
1545+                case '>=':
1546+                    result = (exp1 >= exp2);
1547+                    break;
1548+                case '<=':
1549+                    result = (exp1 === exp2);
1550+                    break;
1551+                case '<>':
1552+                    result = (exp1 != exp2);
1553+                    break;
1554+                case 'NOT':
1555+                    result = (exp1 != exp2);
1556+                    break;
1557+            }
1558+            return result;
1559+        },
1560+        mathMatch: function (type, number1, number2) {
1561+            var result;
1562+            number1 = helper.number(number1);
1563+            number2 = helper.number(number2);
1564+            if (isNaN(number1) || isNaN(number2)) {
1565+                throw Error('VALUE');
1566+            }
1567+            switch (type) {
1568+                case '+':
1569+                    result = number1 + number2;
1570+                    break;
1571+                case '-':
1572+                    result = number1 - number2;
1573+                    break;
1574+                case '/':
1575+                    result = number1 / number2;
1576+                    if (result == Infinity) {
1577+                        throw Error('DIV_ZERO');
1578+                    }
1579+                    else if (isNaN(result)) {
1580+                        throw Error('VALUE');
1581+                    }
1582+                    break;
1583+                case '*':
1584+                    result = number1 * number2;
1585+                    break;
1586+                case '^':
1587+                    result = Math.pow(number1, number2);
1588+                    break;
1589+            }
1590+            return result;
1591+        },
1592+        callFunction: function (fn, args) {
1593+            fn = fn.toUpperCase();
1594+            args = args || [];
1595+            if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
1596+                if (instance.formulas[fn]) {
1597+                    return instance.formulas[fn].apply(this, args);
1598+                }
1599+            }
1600+            throw Error('NAME');
1601+        },
1602+        callVariable: function (args) {
1603+            args = args || [];
1604+            var str = args[0];
1605+            if (str) {
1606+                str = str.toUpperCase();
1607+                if (instance.formulas[str]) {
1608+                    return ((typeof instance.formulas[str] === 'function') ? instance.formulas[str].apply(this, args) : instance.formulas[str]);
1609+                }
1610+            }
1611+            throw Error('NAME');
1612+        },
1613+        cellValue: function (cell) {
1614+            var value, element = this, item = instance.matrix.getItem(cell);
1615+            // get value
1616+            value = item ? item.value : "0"; // TODO: fix this, it's sloppy.
1617+            //update dependencies
1618+            instance.matrix.updateCellItem(element, { deps: [cell] });
1619+            // check references error
1620+            if (item && item.deps) {
1621+                if (item.deps.indexOf(cell) !== -1) {
1622+                    throw Error('REF');
1623+                }
1624+            }
1625+            // check if any error occurs
1626+            if (item && item.error) {
1627+                throw Error(item.error);
1628+            }
1629+            // return value if is set
1630+            if (instance.utils.isSet(value)) {
1631+                var result = instance.helper.number(value);
1632+                return !isNaN(result) ? result : value;
1633+            }
1634+            // cell is not available
1635+            throw Error('NOT_AVAILABLE');
1636+        },
1637+        cellRangeValue: function (start, end) {
1638+            var coordsStart = instance.utils.cellCoords(start), coordsEnd = instance.utils.cellCoords(end), element = this;
1639+            // iterate cells to get values and indexes
1640+            var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd), result = [];
1641+            //update dependencies
1642+            instance.matrix.updateCellItem(element, { deps: cells.index });
1643+            result.push(cells.value);
1644+            return result;
1645+        },
1646+        fixedCellValue: function (id) {
1647+            id = id.replace(/\$/g, '');
1648+            return instance.helper.cellValue.call(this, id);
1649+        },
1650+        fixedCellRangeValue: function (start, end) {
1651+            start = start.replace(/\$/g, '');
1652+            end = end.replace(/\$/g, '');
1653+            return instance.helper.cellRangeValue.call(this, start, end);
1654+        }
1655+    };
1656+    var parse = function (formula, element) {
1657+        var result = null, error = null;
1658+        try {
1659+            parser.setObj(element);
1660+            result = parser.parse(formula);
1661+            var id;
1662+            if (element instanceof HTMLElement) {
1663+                id = element.getAttribute('id');
1664+            }
1665+            else if (element && element.id) {
1666+                id = element.id;
1667+            }
1668+            var deps = instance.matrix.getDependencies(id);
1669+            if (deps.indexOf(id) !== -1) {
1670+                result = null;
1671+                deps.forEach(function (id) {
1672+                    instance.matrix.updateItem(id, { value: null, error: Exception.get('REF') });
1673+                });
1674+                throw Error('REF');
1675+            }
1676+        }
1677+        catch (ex) {
1678+            var message = Exception.get(ex.message);
1679+            if (message) {
1680+                error = message;
1681+            }
1682+            else {
1683+                error = Exception.get('ERROR');
1684+            }
1685+        }
1686+        return {
1687+            error: error,
1688+            result: result
1689+        };
1690+    };
1691+    var init = function () {
1692+        instance = this;
1693+        parser = FormulaParser(instance);
1694+        instance.formulas = Formula;
1695+        instance.matrix = new Matrix();
1696+        instance.custom = {};
1697+        instance.matrix.scan();
1698+    };
1699+    return {
1700+        init: init,
1701+        utils: utils,
1702+        helper: helper,
1703+        parse: parse
1704+    };
1705+});
1706diff --git a/ts/sheet.ts b/ts/sheet.ts
1707new file mode 100644
1708index 0000000..d0611dc
1709--- /dev/null
1710+++ b/ts/sheet.ts
1711@@ -0,0 +1,679 @@
1712+interface P {
1713+  yy: any;
1714+  lexer: any;
1715+  parse: any;
1716+  parseError: any;
1717+}
1718+
1719+declare var Parser: P;
1720+declare var Formula: any;
1721+
1722+var mine = (function () {
1723+  'use strict';
1724+  var instance = this;
1725+
1726+  var parser = {
1727+    setObj: function (thing: any) {
1728+
1729+    },
1730+    parse: function (thing: any) {
1731+
1732+    }
1733+  };
1734+
1735+  var FormulaParser = function(handler) {
1736+    var formulaLexer = function () {};
1737+    formulaLexer.prototype = Parser.lexer;
1738+
1739+    var formulaParser = function () {
1740+      this.lexer = new formulaLexer();
1741+      this.yy = {};
1742+    };
1743+
1744+    formulaParser.prototype = Parser;
1745+    var newParser = new formulaParser;
1746+    newParser.setObj = function(obj) {
1747+      newParser.yy.obj = obj;
1748+    };
1749+
1750+    newParser.yy.parseError = function (str, hash) {
1751+      throw {
1752+        name: 'Parser error',
1753+        message: str,
1754+        prop: hash
1755+      }
1756+    };
1757+
1758+    newParser.yy.handler = handler;
1759+
1760+    return newParser;
1761+  };
1762+
1763+  var Exception = {
1764+    errors: [
1765+      {type: 'NULL', output: '#NULL'},
1766+      {type: 'DIV_ZERO', output: '#DIV/0!'},
1767+      {type: 'VALUE', output: '#VALUE!'},
1768+      {type: 'REF', output: '#REF!'},
1769+      {type: 'NAME', output: '#NAME?'},
1770+      {type: 'NUM', output: '#NUM!'},
1771+      {type: 'NOT_AVAILABLE', output: '#N/A!'},
1772+      {type: 'ERROR', output: '#ERROR'}
1773+    ],
1774+    get: function (type) {
1775+      var error = Exception.errors.filter(function (item) {
1776+        return item.type === type || item.output === type;
1777+      })[0];
1778+
1779+      return error ? error.output : null;
1780+    }
1781+  };
1782+
1783+  var Matrix = function () {
1784+
1785+    // var item = {
1786+    //   id: '',
1787+    //   formula: '',
1788+    //   value: '',
1789+    //   error: '',
1790+    //   deps: [],
1791+    //   formulaEdit: false
1792+    // };
1793+
1794+    this.data = [];
1795+
1796+    this.getItem = function (id) {
1797+      return instance.matrix.data.filter(function (item) {
1798+        return item.id === id;
1799+      })[0];
1800+    };
1801+
1802+    this.removeItem = function (id) {
1803+      instance.matrix.data = instance.matrix.data.filter(function (item) {
1804+        return item.id !== id;
1805+      });
1806+    };
1807+
1808+    this.updateItem = function (item, props) {
1809+      if (instance.utils.isString(item)) {
1810+        item = instance.matrix.getItem(item);
1811+      }
1812+
1813+      if (item && props) {
1814+        for (var p in props) {
1815+          if (item[p] && instance.utils.isArray(item[p])) {
1816+            if (instance.utils.isArray(props[p])) {
1817+              props[p].forEach(function (i) {
1818+                if (item[p].indexOf(i) === -1) {
1819+                  item[p].push(i);
1820+                }
1821+              });
1822+            } else {
1823+
1824+              if (item[p].indexOf(props[p]) === -1) {
1825+                item[p].push(props[p]);
1826+              }
1827+            }
1828+          } else {
1829+            item[p] = props[p];
1830+          }
1831+        }
1832+      }
1833+    };
1834+
1835+    this.addItem = function (item) {
1836+      var cellId = item.id,
1837+        coords = instance.utils.cellCoords(cellId);
1838+
1839+      item.row = coords.row;
1840+      item.col = coords.col;
1841+
1842+      var cellExist = instance.matrix.data.filter(function (cell) {
1843+        return cell.id === cellId;
1844+      })[0];
1845+
1846+      if (!cellExist) {
1847+        instance.matrix.data.push(item);
1848+      } else {
1849+        instance.matrix.updateItem(cellExist, item);
1850+      }
1851+
1852+      return instance.matrix.getItem(cellId);
1853+    };
1854+
1855+
1856+    this.updateCellItem = function (id, props) {
1857+      var item = instance.matrix.getItem(id);
1858+
1859+      instance.matrix.updateItem(item, props);
1860+    };
1861+
1862+    this.getDependencies = function (id) {
1863+      var getDependencies = function (id) {
1864+        var filtered = instance.matrix.data.filter(function (cell) {
1865+          if (cell.deps) {
1866+            return cell.deps.indexOf(id) > -1;
1867+          }
1868+        });
1869+
1870+        var deps = [];
1871+        filtered.forEach(function (cell) {
1872+          if (deps.indexOf(cell.id) === -1) {
1873+            deps.push(cell.id);
1874+          }
1875+        });
1876+
1877+        return deps;
1878+      };
1879+
1880+      var allDependencies = [];
1881+
1882+      var getTotalDependencies = function (id) {
1883+        var deps = getDependencies(id);
1884+
1885+        if (deps.length) {
1886+          deps.forEach(function (refId) {
1887+            if (allDependencies.indexOf(refId) === -1) {
1888+              allDependencies.push(refId);
1889+
1890+              var item = instance.matrix.getItem(refId);
1891+              if (item.deps.length) {
1892+                getTotalDependencies(refId);
1893+              }
1894+            }
1895+          });
1896+        }
1897+      };
1898+
1899+      getTotalDependencies(id);
1900+
1901+      return allDependencies;
1902+    };
1903+
1904+    this.getCellDependencies = function (cell) {
1905+      return instance.matrix.getDependencies(cell.id);
1906+    };
1907+
1908+    var recalculateCellDependencies = function (cell) {
1909+      var allDependencies = instance.matrix.getCellDependencies(cell);
1910+
1911+      allDependencies.forEach(function (refId) {
1912+        var currentCell = instance.matrix.getItem(refId);
1913+        if (currentCell && currentCell.formula) {
1914+          calculateCellFormula(currentCell.formula, currentCell.id);
1915+        }
1916+      });
1917+    };
1918+
1919+    var calculateCellFormula = function (formula, id) {
1920+      // to avoid double translate formulas, update item data in parser
1921+      var parsed = parse(formula, id),
1922+        value = parsed.result,
1923+        error = parsed.error;
1924+
1925+      instance.matrix.updateCellItem(id, {value: value, error: error});
1926+
1927+      return parsed;
1928+    };
1929+
1930+    var registerCellInMatrix = function (cell) {
1931+      instance.matrix.addItem(cell);
1932+      calculateCellFormula(cell.formula, cell.id);
1933+    };
1934+
1935+    this.scan = function () {
1936+      var input = [
1937+        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "SUM(A1:D1, H1)"],
1938+        [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "MAX(A2:J2)"],
1939+        [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "MIN(A3:J3)"],
1940+        [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "AVERAGE(A4:J4)"],
1941+        [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "SUMIF(A5:J5,'>5')"]
1942+      ];
1943+      for (var y = 0; y < input.length; y++) {
1944+        for (var x = 0; x < input[0].length; x++) {
1945+          // set the cell here
1946+          var id = utils.XYtoA1(x, y);
1947+          var cell = {
1948+            id: id,
1949+            formula: input[y][x].toString()
1950+          };
1951+          registerCellInMatrix(cell);
1952+          recalculateCellDependencies(cell);
1953+        }
1954+      }
1955+      console.log(this.data);
1956+    };
1957+  };
1958+
1959+  var utils = {
1960+    isArray: function (value) {
1961+      return Object.prototype.toString.call(value) === '[object Array]';
1962+    },
1963+
1964+    isNumber: function (value) {
1965+      return Object.prototype.toString.call(value) === '[object Number]';
1966+    },
1967+
1968+    isString: function (value) {
1969+      return Object.prototype.toString.call(value) === '[object String]';
1970+    },
1971+
1972+    isFunction: function (value) {
1973+      return Object.prototype.toString.call(value) === '[object Function]';
1974+    },
1975+
1976+    isUndefined: function (value) {
1977+      return Object.prototype.toString.call(value) === '[object Undefined]';
1978+    },
1979+
1980+    isNull: function (value) {
1981+      return Object.prototype.toString.call(value) === '[object Null]';
1982+    },
1983+
1984+    isSet: function (value) {
1985+      return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
1986+    },
1987+
1988+    getCellAlphaNum: function (cell) {
1989+      var num = cell.match(/\d+$/),
1990+        alpha = cell.replace(num, '');
1991+
1992+      return {
1993+        alpha: alpha,
1994+        num: parseInt(num[0], 10)
1995+      }
1996+    },
1997+
1998+    toNum: function (chr) {
1999+      chr = instance.utils.clearFormula(chr);
2000+      var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
2001+
2002+      for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
2003+        result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
2004+      }
2005+
2006+      if (result) {
2007+        --result;
2008+      }
2009+
2010+      return result;
2011+    },
2012+
2013+    toChar: function (num) {
2014+      var s = '';
2015+
2016+      while (num >= 0) {
2017+        s = String.fromCharCode(num % 26 + 97) + s;
2018+        num = Math.floor(num / 26) - 1;
2019+      }
2020+
2021+      return s.toUpperCase();
2022+    },
2023+    XYtoA1: function (x, y) {
2024+      function numberToLetters(num) {
2025+        var mod = num % 26,
2026+          pow = num / 26 | 0,
2027+          out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
2028+        return pow ? numberToLetters(pow) + out : out;
2029+      }
2030+      return numberToLetters(x+1) + (y+1).toString();
2031+    },
2032+    cellCoords: function (cell) {
2033+      var num = cell.match(/\d+$/),
2034+        alpha = cell.replace(num, '');
2035+
2036+      return {
2037+        row: parseInt(num[0], 10) - 1,
2038+        col: instance.utils.toNum(alpha)
2039+      };
2040+    },
2041+
2042+    clearFormula: function (formula) {
2043+      return formula.replace(/\$/g, '');
2044+    },
2045+
2046+    translateCellCoords: function (coords) {
2047+      return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
2048+    },
2049+
2050+    iterateCells: function (startCell, endCell, callback) {
2051+      var result = {
2052+        index: [], // list of cell index: A1, A2, A3
2053+        value: []  // list of cell value
2054+      };
2055+
2056+      var cols = {
2057+        start: 0,
2058+        end: 0
2059+      };
2060+
2061+      if (endCell.col >= startCell.col) {
2062+        cols = {
2063+          start: startCell.col,
2064+          end: endCell.col
2065+        };
2066+      } else {
2067+        cols = {
2068+          start: endCell.col,
2069+          end: startCell.col
2070+        };
2071+      }
2072+
2073+      var rows = {
2074+        start: 0,
2075+        end: 0
2076+      };
2077+
2078+      if (endCell.row >= startCell.row) {
2079+        rows = {
2080+          start: startCell.row,
2081+          end: endCell.row
2082+        };
2083+      } else {
2084+        rows = {
2085+          start: endCell.row,
2086+          end: startCell.row
2087+        };
2088+      }
2089+
2090+      for (var column = cols.start; column <= cols.end; column++) {
2091+        for (var row = rows.start; row <= rows.end; row++) {
2092+          var cellIndex = instance.utils.toChar(column) + (row + 1),
2093+            cellValue = instance.helper.cellValue.call(this, cellIndex);
2094+
2095+          result.index.push(cellIndex);
2096+          result.value.push(cellValue);
2097+        }
2098+      }
2099+
2100+      if (instance.utils.isFunction(callback)) {
2101+        return callback.apply(callback, [result]);
2102+      } else {
2103+        return result;
2104+      }
2105+    },
2106+
2107+    sort: function (rev) {
2108+      return function (a, b) {
2109+        return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
2110+      }
2111+    }
2112+  };
2113+
2114+  var helper = {
2115+    SUPPORTED_FORMULAS: [
2116+      'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
2117+      'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
2118+      'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
2119+      'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
2120+      'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
2121+      'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
2122+      'IF', 'INT', 'ISEVEN', 'ISODD',
2123+      'LN', 'LOG', 'LOG10',
2124+      'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
2125+      'NOT',
2126+      'ODD', 'OR',
2127+      'PI', 'POWER',
2128+      'ROUND', 'ROUNDDOWN', 'ROUNDUP',
2129+      'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
2130+      'TAN', 'TANH', 'TRUE', 'TRUNC',
2131+      'XOR'
2132+    ],
2133+
2134+    number: function (num) {
2135+      switch (typeof num) {
2136+        case 'number':
2137+          return num;
2138+        case 'string':
2139+          if (!isNaN(num)) {
2140+            return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
2141+          }
2142+      }
2143+
2144+      return num;
2145+    },
2146+
2147+    string: function (str) {
2148+      return str.substring(1, str.length - 1);
2149+    },
2150+
2151+    numberInverted: function (num) {
2152+      return this.number(num) * (-1);
2153+    },
2154+
2155+    specialMatch: function (type, exp1, exp2) {
2156+      var result;
2157+
2158+      switch (type) {
2159+        case '&':
2160+          result = exp1.toString() + exp2.toString();
2161+          break;
2162+      }
2163+      return result;
2164+    },
2165+
2166+    logicMatch: function (type, exp1, exp2) {
2167+      var result;
2168+
2169+      switch (type) {
2170+        case '=':
2171+          result = (exp1 === exp2);
2172+          break;
2173+
2174+        case '>':
2175+          result = (exp1 > exp2);
2176+          break;
2177+
2178+        case '<':
2179+          result = (exp1 < exp2);
2180+          break;
2181+
2182+        case '>=':
2183+          result = (exp1 >= exp2);
2184+          break;
2185+
2186+        case '<=':
2187+          result = (exp1 === exp2);
2188+          break;
2189+
2190+        case '<>':
2191+          result = (exp1 != exp2);
2192+          break;
2193+
2194+        case 'NOT':
2195+          result = (exp1 != exp2);
2196+          break;
2197+      }
2198+
2199+      return result;
2200+    },
2201+
2202+    mathMatch: function (type, number1, number2) {
2203+      var result;
2204+
2205+      number1 = helper.number(number1);
2206+      number2 = helper.number(number2);
2207+
2208+      if (isNaN(number1) || isNaN(number2)) {
2209+        throw Error('VALUE');
2210+      }
2211+
2212+      switch (type) {
2213+        case '+':
2214+          result = number1 + number2;
2215+          break;
2216+        case '-':
2217+          result = number1 - number2;
2218+          break;
2219+        case '/':
2220+          result = number1 / number2;
2221+          if (result == Infinity) {
2222+            throw Error('DIV_ZERO');
2223+          } else if (isNaN(result)) {
2224+            throw Error('VALUE');
2225+          }
2226+          break;
2227+        case '*':
2228+          result = number1 * number2;
2229+          break;
2230+        case '^':
2231+          result = Math.pow(number1, number2);
2232+          break;
2233+      }
2234+
2235+      return result;
2236+    },
2237+
2238+    callFunction: function (fn, args) {
2239+      fn = fn.toUpperCase();
2240+      args = args || [];
2241+
2242+      if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
2243+        if (instance.formulas[fn]) {
2244+          return instance.formulas[fn].apply(this, args);
2245+        }
2246+      }
2247+
2248+      throw Error('NAME');
2249+    },
2250+
2251+    callVariable: function (args) {
2252+      args = args || [];
2253+      var str = args[0];
2254+
2255+      if (str) {
2256+        str = str.toUpperCase();
2257+        if (instance.formulas[str]) {
2258+          return ((typeof instance.formulas[str] === 'function') ? instance.formulas[str].apply(this, args) : instance.formulas[str]);
2259+        }
2260+      }
2261+
2262+      throw Error('NAME');
2263+    },
2264+
2265+    cellValue: function (cell) {
2266+      var value,
2267+        element = this,
2268+        item = instance.matrix.getItem(cell);
2269+      // get value
2270+      value = item ? item.value : "0"; // TODO: fix this, it's sloppy.
2271+      //update dependencies
2272+      instance.matrix.updateCellItem(element, {deps: [cell]});
2273+      // check references error
2274+      if (item && item.deps) {
2275+        if (item.deps.indexOf(cell) !== -1) {
2276+          throw Error('REF');
2277+        }
2278+      }
2279+
2280+      // check if any error occurs
2281+      if (item && item.error) {
2282+        throw Error(item.error);
2283+      }
2284+
2285+      // return value if is set
2286+      if (instance.utils.isSet(value)) {
2287+        var result = instance.helper.number(value);
2288+
2289+        return !isNaN(result) ? result : value;
2290+      }
2291+
2292+      // cell is not available
2293+      throw Error('NOT_AVAILABLE');
2294+    },
2295+
2296+    cellRangeValue: function (start, end) {
2297+      var coordsStart = instance.utils.cellCoords(start),
2298+        coordsEnd = instance.utils.cellCoords(end),
2299+        element = this;
2300+
2301+      // iterate cells to get values and indexes
2302+      var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd),
2303+        result = [];
2304+      //update dependencies
2305+      instance.matrix.updateCellItem(element, {deps: cells.index});
2306+
2307+      result.push(cells.value);
2308+      return result;
2309+    },
2310+
2311+    fixedCellValue: function (id) {
2312+      id = id.replace(/\$/g, '');
2313+      return instance.helper.cellValue.call(this, id);
2314+    },
2315+
2316+    fixedCellRangeValue: function (start, end) {
2317+      start = start.replace(/\$/g, '');
2318+      end = end.replace(/\$/g, '');
2319+
2320+      return instance.helper.cellRangeValue.call(this, start, end);
2321+    }
2322+  };
2323+
2324+  var parse = function (formula, element) {
2325+    var result = null,
2326+      error = null;
2327+
2328+    try {
2329+
2330+      parser.setObj(element);
2331+      result = parser.parse(formula);
2332+
2333+      var id;
2334+
2335+      if (element instanceof HTMLElement) {
2336+        id = element.getAttribute('id');
2337+      } else if (element && element.id) {
2338+        id = element.id;
2339+      }
2340+
2341+      var deps = instance.matrix.getDependencies(id);
2342+
2343+      if (deps.indexOf(id) !== -1) {
2344+        result = null;
2345+
2346+        deps.forEach(function (id) {
2347+          instance.matrix.updateItem(id, {value: null, error: Exception.get('REF')});
2348+        });
2349+
2350+        throw Error('REF');
2351+      }
2352+
2353+    } catch (ex) {
2354+
2355+      var message = Exception.get(ex.message);
2356+
2357+      if (message) {
2358+        error = message;
2359+      } else {
2360+        error = Exception.get('ERROR');
2361+      }
2362+    }
2363+
2364+    return {
2365+      error: error,
2366+      result: result
2367+    }
2368+  };
2369+
2370+  var init = function () {
2371+    instance = this;
2372+
2373+    parser = FormulaParser(instance);
2374+
2375+    instance.formulas = Formula;
2376+    instance.matrix = new Matrix();
2377+
2378+    instance.custom = {};
2379+
2380+    instance.matrix.scan();
2381+  };
2382+
2383+  return {
2384+    init: init,
2385+    utils: utils,
2386+    helper: helper,
2387+    parse: parse
2388+  };
2389+
2390+});
2391diff --git a/tsconfig.json b/tsconfig.json
2392new file mode 100644
2393index 0000000..39a290d
2394--- /dev/null
2395+++ b/tsconfig.json
2396@@ -0,0 +1,11 @@
2397+{
2398+  "compilerOptions": {
2399+    "allowJs": true,
2400+    "allowUnreachableCode": true,
2401+    "allowUnusedLabels": true,
2402+    "outDir": "ts"
2403+  },
2404+  "files": [
2405+    "ts/sheet.ts"
2406+  ]
2407+}