      1 /*
      2  JessieCode Interpreter and Compiler
      3
      4     Copyright 2011-2016
      5         Michael Gerhaeuser,
      6         Alfred Wassermann
      7
      8     JessieCode is free software dual licensed under the GNU LGPL or MIT License.
      9
     10     You can redistribute it and/or modify it under the terms of the
     11
     12       * GNU Lesser General Public License as published by
     13         the Free Software Foundation, either version 3 of the License, or
     14         (at your option) any later version
     15       OR
     16       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
     17
     18     JessieCode is distributed in the hope that it will be useful,
     19     but WITHOUT ANY WARRANTY; without even the implied warranty of
     20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     21     GNU Lesser General Public License for more details.
     22
     23     You should have received a copy of the GNU Lesser General Public License and
     24     the MIT License along with JessieCode. If not, see <http://www.gnu.org/licenses/>
     25     and <http://opensource.org/licenses/MIT/>.
     26  */
     27
     28 /*global JXG: true, define: true, window: true, console: true, self: true, document: true, parser: true*/
     29 /*jslint nomen: true, plusplus: true*/
     30
     31 /* depends:
     32  jxg
     33  parser/geonext
     34  base/constants
     35  base/text
     36  math/math
     37  math/geometry
     38  math/statistics
     39  utils/type
     40  utils/uuid
     41  */
     42
     43 /**
     44  * @fileoverview JessieCode is a scripting language designed to provide a
     45  * simple scripting language to build constructions
     46  * with JSXGraph. It is similar to JavaScript, but prevents access to the DOM.
     47  * Hence, it can be used in community driven math portals which want to use
     48  * JSXGraph to display interactive math graphics.
     49  */
     50
     51 define([
     52     'jxg', 'base/constants', 'base/text', 'math/math', 'math/geometry', 'math/statistics', 'utils/type', 'utils/uuid', 'utils/env'
     53 ], function (JXG, Const, Text, Mat, Geometry, Statistics, Type, UUID, Env) {
     54
     55     ;
     56
     57     // IE 6-8 compatibility
     58     if (!Object.create) {
     59         Object.create = function(o, properties) {
     60             if (typeof o !== 'object' && typeof o !== 'function') throw new TypeError('Object prototype may only be an Object: ' + o);
     61             else if (o === null) throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
     62
     63             if (typeof properties != 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
     64
     65             function F() {}
     66
     67             F.prototype = o;
     68
     69             return new F();
     70         };
     71     }
     72
     73     var priv = {
     74             modules: {
     75                 'math': Mat,
     76                 'math/geometry': Geometry,
     77                 'math/statistics': Statistics,
     78                 'math/numerics': Mat.Numerics
     79             }
     80         };
     81
     82     /**
     83      * A JessieCode object provides an interface to the parser and stores all variables and objects used within a JessieCode script.
     84      * The optional argument <tt>code</tt> is interpreted after initializing. To evaluate more code after initializing a JessieCode instance
     85      * please use {@link JXG.JessieCode#parse}. For code snippets like single expressions use {@link JXG.JessieCode#snippet}.
     86      * @constructor
     87      * @param {String} [code] Code to parse.
     88      * @param {Boolean} [geonext=false] Geonext compatibility mode.
     89      */
     90     JXG.JessieCode = function (code, geonext) {
     91         // Control structures
     92
     93         /**
     94          * The global scope.
     95          * @type {Object}
     96          */
     97         this.scope = {
     98             id: 0,
     99             hasChild: true,
    100             args: [],
    101             locals: {},
    102             context: null,
    103             previous: null
    104         };
    105
    106         /**
    107          * Keeps track of all possible scopes every required.
    108          * @type {Array}
    109          */
    110         this.scopes = [];
    111         this.scopes.push(this.scope);
    112
    113         /**
    114          * A stack to store debug information (like line and column where it was defined) of a parameter
    115          * @type Array
    116          * @private
    117          */
    118         this.dpstack = [[]];
    119
    120         /**
    121          * Determines the parameter stack scope.
    122          * @type Number
    123          * @private
    124          */
    125         this.pscope = 0;
    126
    127         /**
    128          * Used to store the property-value definition while parsing an object literal.
    129          * @type Array
    130          * @private
    131          */
    132         this.propstack = [{}];
    133
    134         /**
    135          * The current scope of the object literal stack {@link JXG.JessieCode#propstack}.
    136          * @type Number
    137          * @private
    138          */
    139         this.propscope = 0;
    140
    141         /**
    142          * Store the left hand side of an assignment. If an element is constructed and no attributes are given, this is
    143          * used as the element's name.
    144          * @type Array
    145          * @private
    146          */
    147         this.lhs = [];
    148
    149         /**
    150          * lhs flag, used by JXG.JessieCode#replaceNames
    151          * @type Boolean
    152          * @default false
    153          */
    154         this.isLHS = false;
    155
    156         /**
    157          * The id of an HTML node in which innerHTML all warnings are stored (if no <tt>console</tt> object is available).
    158          * @type String
    159          * @default 'jcwarn'
    160          */
    161         this.warnLog = 'jcwarn';
    162
    163         /**
    164          * Store $log messages in case there's no console.
    165          * @type {Array}
    166          */
    167         this.$log = [];
    168
    169         /**
    170          * Built-in functions and constants
    171          * @type Object
    172          */
    173         this.builtIn = this.defineBuiltIn();
    174
    175         /**
    176          * The board which currently is used to create and look up elements.
    177          * @type JXG.Board
    178          */
    179         this.board = null;
    180
    181         /**
    182          * Keep track of which element is created in which line.
    183          * @type Object
    184          */
    185         this.lineToElement = {};
    186
    187         this.parCurLine = 1;
    188         this.parCurColumn = 0;
    189         this.line = 1;
    190         this.col = 1;
    191
    192         if (JXG.CA) {
    193             this.CA = new JXG.CA(this.node, this.createNode, this);
    194         }
    195
    196         this.code = '';
    197
    198         if (typeof code === 'string') {
    199             this.parse(code, geonext);
    200         }
    201     };
    202
    203
    204     JXG.extend(JXG.JessieCode.prototype, /** @lends JXG.JessieCode.prototype */ {
    205         /**
    206          * Create a new parse tree node.
    207          * @param {String} type Type of node, e.g. node_op, node_var, or node_const
    208          * @param value The nodes value, e.g. a variables value or a functions body.
    209          * @param {Array} children Arbitrary number of child nodes.
    210          */
    211         node: function (type, value, children) {
    212             return {
    213                 type: type,
    214                 value: value,
    215                 children: children
    216             };
    217         },
    218
    219         /**
    220          * Create a new parse tree node. Basically the same as node(), but this builds
    221          * the children part out of an arbitrary number of parameters, instead of one
    222          * array parameter.
    223          * @param {String} type Type of node, e.g. node_op, node_var, or node_const
    224          * @param value The nodes value, e.g. a variables value or a functions body.
    225          * @param children Arbitrary number of parameters; define the child nodes.
    226          */
    227         createNode: function (type, value, children) {
    228             var n = this.node(type, value, []),
    229                 i;
    230
    231             for (i = 2; i < arguments.length; i++) {
    232                 n.children.push(arguments[i]);
    233             }
    234
    235             if (n.type == 'node_const' && Type.isNumber(n.value)) {
    236                 n.isMath = true;
    237             }
    238
    239             n.line = this.parCurLine;
    240             n.col = this.parCurColumn;
    241
    242             return n;
    243         },
    244
    245         /**
    246          * Create a new scope.
    247          * @param {Array} args
    248          * @returns {Object}
    249          */
    250         pushScope: function (args) {
    251             var scope = {
    252                     args: args,
    253                     locals: {},
    254                     context: null,
    255                     previous: this.scope
    256                 };
    257
    258             this.scope.hasChild = true;
    259             this.scope = scope;
    260             scope.id = this.scopes.push(scope) - 1;
    261
    262             return scope;
    263         },
    264
    265         /**
    266          * Remove the current scope and reinstate the previous scope
    267          * @returns {Object}
    268          */
    269         popScope: function () {
    270             var s = this.scope.previous;
    271
    272             // make sure the global scope is not lost
    273             this.scope = s !== null ? s : this.scope;
    274
    275             return this.scope;
    276         },
    277
    278         /**
    279          * Looks up an {@link JXG.GeometryElement} by its id.
    280          * @param {String} id
    281          * @returns {JXG.GeometryElement}
    282          */
    283         getElementById: function (id) {
    284             return this.board.objects[id];
    285         },
    286
    287         log: function () {
    288             this.$log.push(arguments);
    289
    290             if (typeof console === 'object' && console.log) {
    291                 console.log.apply(console, arguments);
    292             }
    293         },
    294
    295         /**
    296          * Returns a element creator function which takes two parameters: the parents array and the attributes object.
    297          * @param {String} vname The element type, e.g. 'point', 'line', 'midpoint'
    298          * @returns {function}
    299          */
    300         creator: (function () {
    301             // stores the already defined creators
    302             var _ccache = {}, r;
    303
    304             r = function (vname) {
    305                 var f;
    306
    307                 // _ccache is global, i.e. it is the same for ALL JessieCode instances.
    308                 // That's why we need the board id here
    309                 if (typeof _ccache[this.board.id + vname] === 'function') {
    310                     f =  _ccache[this.board.id + vname];
    311                 } else {
    312                     f = (function (that) {
    313                         return function (parameters, attributes) {
    314                             var attr;
    315
    316                             if (Type.exists(attributes)) {
    317                                 attr = attributes;
    318                             } else {
    319                                 attr = {name: (that.lhs[that.scope] !== 0 ? that.lhs[that.scope] : '')};
    320                             }
    321                             return that.board.create(vname, parameters, attr);
    322                         };
    323                     }(this));
    324
    325                     f.creator = true;
    326                     _ccache[this.board.id + vname] = f;
    327                 }
    328
    329                 return f;
    330             };
    331
    332             r.clearCache = function () {
    333                 _ccache = {};
    334             };
    335
    336             return r;
    337         }()),
    338
    339         /**
    340          * Assigns a value to a variable in the current scope.
    341          * @param {String} vname Variable name
    342          * @param value Anything
    343          * @see JXG.JessieCode#sstack
    344          * @see JXG.JessieCode#scope
    345          */
    346         letvar: function (vname, value) {
    347             if (this.builtIn[vname]) {
    348                 this._warn('"' + vname + '" is a predefined value.');
    349             }
    350
    351             this.scope.locals[vname] = value;
    352         },
    353
    354         /**
    355          * Checks if the given variable name can be found in the current scope chain.
    356          * @param {String} vname
    357          * @returns {Object} A reference to the scope object the variable can be found in or null if it can't be found.
    358          */
    359         isLocalVariable: function (vname) {
    360             var s = this.scope;
    361
    362             while (s !== null) {
    363                 if (Type.exists(s.locals[vname])) {
    364                     return s;
    365                 }
    366
    367                 s = s.previous;
    368             }
    369
    370             return null;
    371         },
    372
    373         /**
    374          * Checks if the given variable name is a parameter in any scope from the current to the global scope.
    375          * @param {String} vname
    376          * @returns {Object} A reference to the scope object that contains the variable in its arg list.
    377          */
    378         isParameter: function (vname) {
    379             var s = this.scope;
    380
    381             while (s !== null) {
    382                 if (Type.indexOf(s.args, vname) > -1) {
    383                     return s;
    384                 }
    385
    386                 s = s.previous;
    387             }
    388
    389             return null;
    390         },
    391
    392         /**
    393          * Checks if the given variable name is a valid creator method.
    394          * @param {String} vname
    395          * @returns {Boolean}
    396          */
    397         isCreator: function (vname) {
    398             // check for an element with this name
    399             return !!JXG.elements[vname];
    400         },
    401
    402         /**
    403          * Checks if the given variable identifier is a valid member of the JavaScript Math Object.
    404          * @param {String} vname
    405          * @returns {Boolean}
    406          */
    407         isMathMethod: function (vname) {
    408             return vname !== 'E' && !!Math[vname];
    409         },
    410
    411         /**
    412          * Returns true if the given identifier is a builtIn variable/function.
    413          * @param {String} vname
    414          * @returns {Boolean}
    415          */
    416         isBuiltIn: function (vname) {
    417             return !!this.builtIn[vname];
    418         },
    419
    420         /**
    421          * Looks up the value of the given variable.
    422          * @param {String} vname Name of the variable
    423          * @param {Boolean} [local=false] Only look up the internal symbol table and don't look for
    424          * the <tt>vname</tt> in Math or the element list.
    425          */
    426         getvar: function (vname, local) {
    427             var s;
    428
    429             local = Type.def(local, false);
    430
    431             s = this.isLocalVariable(vname);
    432             if (s !== null) {
    433                 return s.locals[vname];
    434             }
    435
    436             // check for an element with this name
    437             if (this.isCreator(vname)) {
    438                 return this.creator(vname);
    439             }
    440
    441             if (this.isBuiltIn(vname)) {
    442                 return this.builtIn[vname];
    443             }
    444
    445             if (this.isMathMethod(vname)) {
    446                 return Math[vname];
    447             }
    448
    449             if (!local) {
    450                 s = this.board.select(vname);
    451                 if (s !== vname) {
    452                     return s;
    453                 }
    454             }
    455         },
    456
    457         /**
    458          * Look up the value of a local variable.
    459          * @param {string} vname
    460          * @returns {*}
    461          */
    462         resolve: function (vname) {
    463             var s = this.scope;
    464
    465             while (s !== null) {
    466                 if (Type.exists(s.locals[vname])) {
    467                     return s.locals[vname];
    468                 }
    469
    470                 s = s.previous;
    471             }
    472         },
    473
    474         /**
    475          * TODO this needs to be called from JS and should not generate JS code
    476          * Looks up a variable identifier in various tables and generates JavaScript code that could be eval'd to get the value.
    477          * @param {String} vname Identifier
    478          * @param {Boolean} [local=false] Don't resolve ids and names of elements
    479          * @param {Boolean} [withProps=false]
    480          */
    481         getvarJS: function (vname, local, withProps) {
    482             var s, r = '';
    483
    484             local = Type.def(local, false);
    485             withProps = Type.def(withProps, false);
    486
    487             s = this.isParameter(vname);
    488             if (s !== null) {
    489                 return vname;
    490             }
    491
    492             s = this.isLocalVariable(vname);
    493             if (s !== null && !withProps) {
    494                 return '$jc$.resolve(\'' + vname + '\')';
    495             }
    496
    497             // check for an element with this name
    498             if (this.isCreator(vname)) {
    499                 return '(function () { var a = Array.prototype.slice.call(arguments, 0), props = ' + (withProps ? 'a.pop()' : '{}') + '; return $jc$.board.create.apply($jc$.board, [\'' + vname + '\'].concat([a, props])); })';
    500             }
    501
    502             if (withProps) {
    503                 this._error('Syntax error (attribute values are allowed with element creators only)');
    504             }
    505
    506             if (this.isBuiltIn(vname)) {
    507                 // if src does not exist, it is a number. in that case, just return the value.
    508                 return this.builtIn[vname].src || this.builtIn[vname];
    509             }
    510
    511             if (this.isMathMethod(vname)) {
    512                 return 'Math.' + vname;
    513             }
    514
    515             if (!local) {
    516                 if (Type.isId(this.board, vname)) {
    517                     r = '$jc$.board.objects[\'' + vname + '\']';
    518                 } else if (Type.isName(this.board, vname)) {
    519                     r = '$jc$.board.elementsByName[\'' + vname + '\']';
    520                 } else if (Type.isGroup(this.board, vname)) {
    521                     r = '$jc$.board.groups[\'' + vname + '\']';
    522                 }
    523
    524                 return r;
    525             }
    526
    527             return '';
    528         },
    529
    530         /**
    531          * Adds the property <tt>isMap</tt> to a function and sets it to true.
    532          * @param {function} f
    533          * @returns {function}
    534          */
    535         makeMap: function (f) {
    536             f.isMap = true;
    537
    538             return f;
    539         },
    540
    541         functionCodeJS: function (node) {
    542             var p = node.children[0].join(', '),
    543                 bo = '',
    544                 bc = '';
    545
    546             if (node.value === 'op_map') {
    547                 bo = '{ return  ';
    548                 bc = ' }';
    549             }
    550
    551             return 'function (' + p + ') {\n' +
    552                     'var $oldscope$ = $jc$.scope;\n' +
    553                     '$jc$.scope = $jc$.scopes[' + this.scope.id + '];\n' +
    554                     'var r = (function () ' + bo + this.compile(node.children[1], true) + bc + ')();\n' +
    555                     '$jc$.scope = $oldscope$;\n' +
    556                     'return r;\n' +
    557                 '}';
    558         },
    559
    560         /**
    561          * Converts a node type <tt>node_op</tt> and value <tt>op_map</tt> or <tt>op_function</tt> into a executable
    562          * function.
    563          * @param {Object} node
    564          * @returns {function}
    565          */
    566         defineFunction: function (node) {
    567             var fun, i,
    568                 list = node.children[0],
    569                 scope = this.pushScope(list);
    570
    571             if (this.board.options.jc.compile) {
    572                 this.isLHS = false;
    573
    574                 // we currently need to put the parameters into the local scope
    575                 // until the compiled JS variable lookup code is fixed
    576                 for (i = 0; i < list.length; i++) {
    577                     scope.locals[list[i]] = list[i];
    578                 }
    579
    580                 this.replaceNames(node.children[1]);
    581
    582                 fun = (function ($jc$) {
    583                     var fun,
    584                         str = 'var f = ' + $jc$.functionCodeJS(node) + '; f;';
    585
    586                     try {
    587                         // yeah, eval is evil, but we don't have much choice here.
    588                         // the str is well defined and there is no user input in it that we didn't check before
    589
    590                         /*jslint evil:true*/
    591                         fun = eval(str);
    592                         /*jslint evil:false*/
    593
    594                         return fun;
    595                     } catch (e) {
    596                         $jc$._warn('error compiling function\n\n' + str + '\n\n' + e.toString());
    597                         return function () {};
    598                     }
    599                 }(this));
    600
    601                 // clean up scope
    602                 this.popScope();
    603             } else {
    604                 fun = (function (_pstack, that, id) {
    605                     return function () {
    606                         var r, oldscope;
    607
    608                         oldscope = that.scope;
    609                         that.scope = that.scopes[id];
    610
    611                         for (r = 0; r < _pstack.length; r++) {
    612                             that.scope.locals[_pstack[r]] = arguments[r];
    613                         }
    614
    615                         r = that.execute(node.children[1]);
    616                         that.scope = oldscope;
    617
    618                         return r;
    619                     };
    620                 }(list, this, scope.id));
    621             }
    622
    623             fun.node = node;
    624             fun.scope = scope;
    625             fun.toJS = fun.toString;
    626             fun.toString = (function (_that) {
    627                 return function () {
    628                     return _that.compile(_that.replaceIDs(Type.deepCopy(node)));
    629                 };
    630             }(this));
    631
    632             fun.deps = {};
    633             this.collectDependencies(node.children[1], fun.deps);
    634
    635             return fun;
    636         },
    637
    638         /**
    639          * Merge all attribute values given with an element creator into one object.
    640          * @param {Object} o An arbitrary number of objects
    641          * @returns {Object} All given objects merged into one. If properties appear in more (case sensitive) than one
    642          * object the last value is taken.
    643          */
    644         mergeAttributes: function (o) {
    645             var i, attr = {};
    646
    647             for (i = 0; i < arguments.length; i++) {
    648                 attr = Type.deepCopy(attr, arguments[i], true);
    649             }
    650
    651             return attr;
    652         },
    653
    654         /**
    655          * Sets the property <tt>what</tt> of <tt>o</tt> to <tt>value</tt>
    656          * @param {JXG.Point|JXG.Text} o
    657          * @param {String} what
    658          * @param value
    659          */
    660         setProp: function (o, what, value) {
    661             var par = {}, x, y;
    662
    663             if (o.elementClass === Const.OBJECT_CLASS_POINT && (what === 'X' || what === 'Y')) {
    664                 // set coords
    665
    666                 what = what.toLowerCase();
    667
    668                 // we have to deal with three cases here:
    669                 // o.isDraggable && typeof value === number:
    670                 //   stay draggable, just set the new coords (e.g. via moveTo)
    671                 // o.isDraggable && typeof value === function:
    672                 //   convert to !o.isDraggable, set the new coords via o.addConstraint()
    673                 // !o.isDraggable:
    674                 //   stay !o.isDraggable, update the given coord by overwriting X/YEval
    675
    676                 if (o.isDraggable && typeof value === 'number') {
    677                     x = what === 'x' ? value : o.X();
    678                     y = what === 'y' ? value : o.Y();
    679
    680                     o.setPosition(Const.COORDS_BY_USER, [x, y]);
    681                 } else if (o.isDraggable && (typeof value === 'function' || typeof value === 'string')) {
    682                     x = what === 'x' ? value : o.coords.usrCoords[1];
    683                     y = what === 'y' ? value : o.coords.usrCoords[2];
    684
    685                     o.addConstraint([x, y]);
    686                 } else if (!o.isDraggable) {
    687                     x = what === 'x' ? value : o.XEval.origin;
    688                     y = what === 'y' ? value : o.YEval.origin;
    689
    690                     o.addConstraint([x, y]);
    691                 }
    692
    693                 this.board.update();
    694             } else if (o.elementClass === Const.OBJECT_CLASS_TEXT && (what === 'X' || what === 'Y')) {
    695                 if (typeof value === 'number') {
    696                     o[what] = function () { return value; };
    697                 } else if (typeof value === 'function') {
    698                     o.isDraggable = false;
    699                     o[what] = value;
    700                 } else if (typeof value === 'string') {
    701                     o.isDraggable = false;
    702                     o[what] = Type.createFunction(value, this.board, null, true);
    703                     o[what + 'jc'] = value;
    704                 }
    705
    706                 o[what].origin = value;
    707
    708                 this.board.update();
    709             } else if (o.type && o.elementClass && o.visProp) {
    710                 if (Type.exists(o[o.methodMap[what]]) && typeof o[o.methodMap[what]] !== 'function') {
    711                     o[o.methodMap[what]] = value;
    712                 } else {
    713                     par[what] = value;
    714                     o.setAttribute(par);
    715                 }
    716             } else {
    717                 o[what] = value;
    718             }
    719         },
    720
    721         /**
    722          * Generic method to parse JessieCode.
    723          * This consists of generating an AST with parser.parse,
    724          * apply simplifying rules from CA and
    725          * manipulate the AST according to the second parameter "cmd".
    726          * @param  {String} code      JessieCode code to be parsed
    727          * @param  {String} cmd       Type of manipulation to be done with AST
    728          * @param {Boolean} [geonext=false] Geonext compatibility mode.
    729          * @param {Boolean} dontstore If false, the code string is stored in this.code.
    730          * @return {Object}           Returns result of computation as directed in cmd.
    731          */
    732         _genericParse:  function (code, cmd, geonext, dontstore) {
    733             var i, setTextBackup, ast, result,
    734                 ccode = code.replace(/\r\n/g, '\n').split('\n'),
    735                 cleaned = [];
    736
    737             if (!dontstore) {
    738                 this.code += code + '\n';
    739             }
    740
    741             if (Text) {
    742                 setTextBackup = Text.Text.prototype.setText;
    743                 Text.Text.prototype.setText = Text.Text.prototype.setTextJessieCode;
    744             }
    745
    746             try {
    747                 if (!Type.exists(geonext)) {
    748                     geonext = false;
    749                 }
    750
    751                 for (i = 0; i < ccode.length; i++) {
    752                     if (geonext) {
    753                         ccode[i] = JXG.GeonextParser.geonext2JS(ccode[i], this.board);
    754                     }
    755                     cleaned.push(ccode[i]);
    756                 }
    757
    758                 code = cleaned.join('\n');
    759                 ast = parser.parse(code);
    760                 if (this.CA) {
    761                     ast = this.CA.expandDerivatives(ast, null, ast);
    762                     ast = this.CA.removeTrivialNodes(ast);
    763                 }
    764                 switch (cmd) {
    765                     case 'parse':
    766                         result = this.execute(ast);
    767                         break;
    768                     case 'manipulate':
    769                         result = this.compile(ast);
    770                         break;
    771                     case 'getAst':
    772                         result = ast;
    773                         break;
    774                     default:
    775                         result = false;
    776                 }
    777             } catch (e) {  // catch is mandatory in old IEs
    778                 console.log(e);
    779             } finally {
    780                 // make sure the original text method is back in place
    781                 if (Text) {
    782                     Text.Text.prototype.setText = setTextBackup;
    783                 }
    784             }
    785
    786             return result;
    787         },
    788
    789         /**
    790          * Parses JessieCode.
    791          * This consists of generating an AST with parser.parse, apply simplifying rules
    792          * from CA and executing the ast by calling this.execute(ast).
    793          *
    794          * @param {String} code             JessieCode code to be parsed
    795          * @param {Boolean} [geonext=false] Geonext compatibility mode.
    796          * @param {Boolean} dontstore       If false, the code string is stored in this.code.
    797          * @private
    798          * @return {Object}                 Parse JessieCode code and execute it..
    799          */
    800         parse: function (code, geonext, dontstore) {
    801             return this._genericParse(code, 'parse', geonext, dontstore);
    802         },
    803
    804         /**
    805          * Manipulate JessieCode.
    806          * This consists of generating an AST with parser.parse,
    807          * apply simlifying rules from CA
    808          * and compile the AST back to JessieCode.
    809          *
    810          * @param {String} code             JessieCode code to be parsed
    811          * @param {Boolean} [geonext=false] Geonext compatibility mode.
    812          * @param {Boolean} dontstore       If false, the code string is stored in this.code.
    813          * @return {String}                 Simplified JessieCode code
    814          */
    815         manipulate: function (code, geonext, dontstore) {
    816             return this._genericParse(code, 'manipulate', geonext, dontstore);
    817         },
    818
    819         /**
    820          * Get abstract syntax tree (AST) from JessieCode code.
    821          * This consists of generating an AST with parser.parse.
    822          *
    823          * @param {String} code
    824          * @param {Boolean} [geonext=false] Geonext compatibility mode.
    825          * @param {Boolean} dontstore
    826          * @return {Node}  AST
    827          */
    828         getAST: function (code, geonext, dontstore) {
    829             return this._genericParse(code, 'getAst', geonext, dontstore);
    830         },
    831
    832         /**
    833          * Parses a JessieCode snippet, e.g. "3+4", and wraps it into a function, if desired.
    834          * @param {String} code A small snippet of JessieCode. Must not be an assignment.
    835          * @param {Boolean} funwrap If true, the code is wrapped in a function.
    836          * @param {String} varname Name of the parameter(s)
    837          * @param {Boolean} [geonext=false] Geonext compatibility mode.
    838          */
    839         snippet: function (code, funwrap, varname, geonext) {
    840             var c;
    841
    842             funwrap = Type.def(funwrap, true);
    843             varname = Type.def(varname, '');
    844             geonext = Type.def(geonext, false);
    845
    846             c = (funwrap ? ' function (' + varname + ') { return ' : '') + code + (funwrap ? '; }' : '') + ';';
    847
    848             return this.parse(c, geonext, true);
    849         },
    850
    851         /**
    852          * Traverses through the given subtree and changes all values of nodes with the replaced flag set by
    853          * {@link JXG.JessieCode#replaceNames} to the name of the element (if not empty).
    854          * @param {Object} node
    855          */
    856         replaceIDs: function (node) {
    857             var i, v;
    858
    859             if (node.replaced) {
    860                 // these children exist, if node.replaced is set.
    861                 v = this.board.objects[node.children[1][0].value];
    862
    863                 if (Type.exists(v) && v.name !== "") {
    864                     node.type = 'node_var';
    865                     node.value = v.name;
    866
    867                     // maybe it's not necessary, but just to be sure that everything is cleaned up we better delete all
    868                     // children and the replaced flag
    869                     node.children.length = 0;
    870                     delete node.replaced;
    871                 }
    872             }
    873
    874             if (node.children) {
    875                 // assignments are first evaluated on the right hand side
    876                 for (i = node.children.length; i > 0; i--) {
    877                     if (Type.exists(node.children[i - 1])) {
    878                         node.children[i - 1] = this.replaceIDs(node.children[i - 1]);
    879                     }
    880
    881                 }
    882             }
    883
    884             return node;
    885         },
    886
    887         /**
    888          * Traverses through the given subtree and changes all elements referenced by names through referencing them by ID.
    889          * An identifier is only replaced if it is not found in all scopes above the current scope and if it
    890          * has not been blacklisted within the codeblock determined by the given subtree.
    891          * @param {Object} node
    892          */
    893         replaceNames: function (node) {
    894             var i, v;
    895
    896             v = node.value;
    897
    898             // we are interested only in nodes of type node_var and node_op > op_lhs.
    899             // currently, we are not checking if the id is a local variable. in this case, we're stuck anyway.
    900
    901             if (node.type === 'node_op' && v === 'op_lhs' && node.children.length === 1) {
    902                 this.isLHS = true;
    903             } else if (node.type === 'node_var') {
    904                 if (this.isLHS) {
    905                     this.letvar(v, true);
    906                 } else if (!Type.exists(this.getvar(v, true)) && Type.exists(this.board.elementsByName[v])) {
    907                     node = this.createReplacementNode(node);
    908                 }
    909             }
    910
    911             if (node.children) {
    912                 // assignments are first evaluated on the right hand side
    913                 for (i = node.children.length; i > 0; i--) {
    914                     if (Type.exists(node.children[i - 1])) {
    915                         node.children[i - 1] = this.replaceNames(node.children[i - 1]);
    916                     }
    917                 }
    918             }
    919
    920             if (node.type === 'node_op' && node.value === 'op_lhs' && node.children.length === 1) {
    921                 this.isLHS = false;
    922             }
    923
    924             return node;
    925         },
    926
    927         /**
    928          * Replaces node_var nodes with node_op>op_execfun nodes, calling the internal $() function with the id of the
    929          * element accessed by the node_var node.
    930          * @param {Object} node
    931          * @returns {Object} op_execfun node
    932          */
    933         createReplacementNode: function (node) {
    934             var v = node.value,
    935                 el = this.board.elementsByName[v];
    936
    937             node = this.createNode('node_op', 'op_execfun',
    938                 this.createNode('node_var', '$'),
    939                 [this.createNode('node_str', el.id)]);
    940
    941             node.replaced = true;
    942
    943             return node;
    944         },
    945
    946         /**
    947          * Search the parse tree below <tt>node</tt> for <em>stationary</em> dependencies, i.e. dependencies hard coded into
    948          * the function.
    949          * @param {Object} node
    950          * @param {Object} result An object where the referenced elements will be stored. Access key is their id.
    951          */
    952         collectDependencies: function (node, result) {
    953             var i, v, e;
    954
    955             v = node.value;
    956
    957             if (node.type === 'node_var') {
    958                 e = this.getvar(v);
    959                 if (e && e.visProp && e.type && e.elementClass && e.id) {
    960                     result[e.id] = e;
    961                 }
    962             }
    963
    964             // the $()-function-calls are special because their parameter is given as a string, not as a node_var.
    965             if (node.type === 'node_op' && node.value === 'op_execfun' && node.children.length > 1 && node.children[0].value === '$' && node.children[1].length > 0) {
    966                 e = node.children[1][0].value;
    967                 result[e] = this.board.objects[e];
    968             }
    969
    970             if (node.children) {
    971                 for (i = node.children.length; i > 0; i--) {
    972                     if (Type.exists(node.children[i - 1])) {
    973                         this.collectDependencies(node.children[i - 1], result);
    974                     }
    975
    976                 }
    977             }
    978         },
    979
    980         resolveProperty: function (e, v, compile) {
    981             compile = Type.def(compile, false);
    982
    983             // is it a geometry element or a board?
    984             if (e /*&& e.type && e.elementClass*/ && e.methodMap) {
    985                 // yeah, it is. but what does the user want?
    986                 if (Type.exists(e.subs) && Type.exists(e.subs[v])) {
    987                     // a subelement it is, good sir.
    988                     e = e.subs;
    989                 } else if (Type.exists(e.methodMap[v])) {
    990                     // the user wants to call a method
    991                     v = e.methodMap[v];
    992                 } else {
    993                     // the user wants to change an attribute
    994                     e = e.visProp;
    995                     v = v.toLowerCase();
    996                 }
    997             }
    998
    999             if (Type.isFunction(e)) {
    1000                 this._error('Accessing function properties is not allowed.');
    1001             }
    1002
    1003             if (!Type.exists(e)) {
    1004                 this._error(e + ' is not an object');
    1005             }
    1006
    1007             if (!Type.exists(e[v])) {
    1008                 this._error('unknown property ' + v);
    1009             }
    1010
    1011             if (compile && typeof e[v] === 'function') {
    1012                 return function () { return e[v].apply(e, arguments); };
    1013             }
    1014
    1015             return e[v];
    1016         },
    1017
    1018         /**
    1019          * Resolves the lefthand side of an assignment operation
    1020          * @param node
    1021          * @returns {Object} An object with two properties. <strong>o</strong> which contains the object, and
    1022          * a string <strong>what</strong> which contains the property name.
    1023          */
    1024         getLHS: function (node) {
    1025             var res;
    1026
    1027             if (node.type === 'node_var') {
    1028                 res = {
    1029                     o: this.scope.locals,
    1030                     what: node.value
    1031                 };
    1032             } else if (node.type === 'node_op' && node.value === 'op_property') {
    1033                 res = {
    1034                     o: this.execute(node.children[0]),
    1035                     what: node.children[1]
    1036                 };
    1037             } else if (node.type === 'node_op' && node.value === 'op_extvalue') {
    1038                 res = {
    1039                     o: this.execute(node.children[0]),
    1040                     what: this.execute(node.children[1])
    1041                 };
    1042             } else {
    1043                 throw new Error('Syntax error: Invalid left-hand side of assignment.');
    1044             }
    1045
    1046             return res;
    1047         },
    1048
    1049         getLHSCompiler: function (node, js) {
    1050             var res;
    1051
    1052             if (node.type === 'node_var') {
    1053                 res = node.value;
    1054             } else if (node.type === 'node_op' && node.value === 'op_property') {
    1055                 res = [
    1056                     this.compile(node.children[0], js),
    1057                     "'" + node.children[1] + "'"
    1058                 ];
    1059             } else if (node.type === 'node_op' && node.value === 'op_extvalue') {
    1060                 res = [
    1061                     this.compile(node.children[0], js),
    1062                     node.children[1].type === 'node_const' ? node.children[1].value : this.compile(node.children[1], js)
    1063                 ];
    1064             } else {
    1065                 throw new Error('Syntax error: Invalid left-hand side of assignment.');
    1066             }
    1067
    1068             return res;
    1069         },
    1070
    1071         /**
    1072          * Executes a parse subtree.
    1073          * @param {Object} node
    1074          * @returns {Number|String|Object|Boolean} Something
    1075          * @private
    1076          */
    1077         execute: function (node) {
    1078             var ret, v, i, e, l, undef, list, ilist,
    1079                 parents = [],
    1080                 // exec fun
    1081                 fun, attr, sc;
    1082
    1083             ret = 0;
    1084
    1085             if (!node) {
    1086                 return ret;
    1087             }
    1088
    1089             this.line = node.line;
    1090             this.col = node.col;
    1091
    1092             switch (node.type) {
    1093             case 'node_op':
    1094                 switch (node.value) {
    1095                 case 'op_none':
    1096                     if (node.children[0]) {
    1097                         this.execute(node.children[0]);
    1098                     }
    1099                     if (node.children[1]) {
    1100                         ret = this.execute(node.children[1]);
    1101                     }
    1102                     break;
    1103                 case 'op_assign':
    1104                     v = this.getLHS(node.children[0]);
    1105                     this.lhs[this.scope.id] = v[1];
    1106
    1107                     if (v.o.type && v.o.elementClass && v.o.methodMap && v.what === 'label') {
    1108                         this._error('Left-hand side of assignment is read-only.');
    1109                     }
    1110
    1111                     ret = this.execute(node.children[1]);
    1112                     if (v.o !== this.scope.locals || (Type.isArray(v.o) && typeof v.what === 'number')) {
    1113                         // it is either an array component being set or a property of an object.
    1114                         this.setProp(v.o, v.what, ret);
    1115                     } else {
    1116                         // this is just a local variable inside JessieCode
    1117                         this.letvar(v.what, ret);
    1118                     }
    1119                     this.lhs[this.scope.id] = 0;
    1120                     break;
    1121                 case 'op_if':
    1122                     if (this.execute(node.children[0])) {
    1123                         ret = this.execute(node.children[1]);
    1124                     }
    1125                     break;
    1126                 case 'op_conditional':
    1127                     // fall through
    1128                 case 'op_if_else':
    1129                     if (this.execute(node.children[0])) {
    1130                         ret = this.execute(node.children[1]);
    1131                     } else {
    1132                         ret = this.execute(node.children[2]);
    1133                     }
    1134                     break;
    1135                 case 'op_while':
    1136                     while (this.execute(node.children[0])) {
    1137                         this.execute(node.children[1]);
    1138                     }
    1139                     break;
    1140                 case 'op_do':
    1141                     do {
    1142                         this.execute(node.children[0]);
    1143                     } while (this.execute(node.children[1]));
    1144                     break;
    1145                 case 'op_for':
    1146                     for (this.execute(node.children[0]); this.execute(node.children[1]); this.execute(node.children[2])) {
    1147                         this.execute(node.children[3]);
    1148                     }
    1149                     break;
    1150                 case 'op_proplst':
    1151                     if (node.children[0]) {
    1152                         this.execute(node.children[0]);
    1153                     }
    1154                     if (node.children[1]) {
    1155                         this.execute(node.children[1]);
    1156                     }
    1157                     break;
    1158                 case 'op_emptyobject':
    1159                     ret = {};
    1160                     break;
    1161                 case 'op_proplst_val':
    1162                     this.propstack.push({});
    1163                     this.propscope++;
    1164
    1165                     this.execute(node.children[0]);
    1166                     ret = this.propstack[this.propscope];
    1167
    1168                     this.propstack.pop();
    1169                     this.propscope--;
    1170                     break;
    1171                 case 'op_prop':
    1172                     // child 0: Identifier
    1173                     // child 1: Value
    1174                     this.propstack[this.propscope][node.children[0]] = this.execute(node.children[1]);
    1175                     break;
    1176                 case 'op_array':
    1177                     ret = [];
    1178                     l = node.children[0].length;
    1179
    1180                     for (i = 0; i < l; i++) {
    1181                         ret.push(this.execute(node.children[0][i]));
    1182                     }
    1183
    1184                     break;
    1185                 case 'op_extvalue':
    1186                     ret = this.execute(node.children[0]);
    1187                     i = this.execute(node.children[1]);
    1188
    1189                     if (typeof i === 'number' && Math.abs(Math.round(i) - i) < Mat.eps) {
    1190                         ret = ret[i];
    1191                     } else {
    1192                         ret = undef;
    1193                     }
    1194                     break;
    1195                 case 'op_return':
    1196                     if (this.scope === 0) {
    1197                         this._error('Unexpected return.');
    1198                     } else {
    1199                         return this.execute(node.children[0]);
    1200                     }
    1201                     break;
    1202                 case 'op_map':
    1203                     if (!node.children[1].isMath && node.children[1].type !== 'node_var') {
    1204                         this._error('execute: In a map only function calls and mathematical expressions are allowed.');
    1205                     }
    1206
    1207                     fun = this.defineFunction(node);
    1208                     fun.isMap = true;
    1209
    1210                     ret = fun;
    1211                     break;
    1212                 case 'op_function':
    1213                     // parse the parameter list
    1214                     // after this, the parameters are in pstack
    1215
    1216                     fun = this.defineFunction(node);
    1217                     fun.isMap = false;
    1218
    1219                     ret = fun;
    1220                     break;
    1221                 case 'op_execfun':
    1222                     // node.children:
    1223                     //   [0]: Name of the function
    1224                     //   [1]: Parameter list as a parse subtree
    1225                     //   [2]: Properties, only used in case of a create function
    1226                     this.dpstack.push([]);
    1227                     this.pscope++;
    1228
    1229                     // parameter parsing is done below
    1230                     list = node.children[1];
    1231
    1232                     // parse the properties only if given
    1233                     if (Type.exists(node.children[2])) {
    1234                         if (node.children[3]) {
    1235                             ilist = node.children[2];
    1236                             attr = {};
    1237
    1238                             for (i = 0; i < ilist.length; i++) {
    1239                                 attr = Type.deepCopy(attr, this.execute(ilist[i]), true);
    1240                             }
    1241                         } else {
    1242                             attr = this.execute(node.children[2]);
    1243                         }
    1244                     }
    1245
    1246                     // look up the variables name in the variable table
    1247                     fun = this.execute(node.children[0]);
    1248
    1249                     // determine the scope the function wants to run in
    1250                     if (fun && fun.sc) {
    1251                         sc = fun.sc;
    1252                     } else {
    1253                         sc = this;
    1254                     }
    1255
    1256                     if (!fun.creator && Type.exists(node.children[2])) {
    1257                         this._error('Unexpected value. Only element creators are allowed to have a value after the function call.');
    1258                     }
    1259
    1260                     // interpret ALL the parameters
    1261                     for (i = 0; i < list.length; i++) {
    1262                         parents[i] = this.execute(list[i]);
    1263                         //parents[i] = Type.evalSlider(this.execute(list[i]));
    1264                         this.dpstack[this.pscope].push({
    1265                             line: node.children[1][i].line,
    1266                             // SketchBin currently works only if the last column of the
    1267                             // parent position is taken. This is due to how I patched JS/CC
    1268                             // to count the lines and columns. So, ecol will do for now
    1269                             col: node.children[1][i].ecol
    1270                         });
    1271                     }
    1272
    1273                     // check for the function in the variable table
    1274                     if (typeof fun === 'function' && !fun.creator) {
    1275                         ret = fun.apply(sc, parents);
    1276                     } else if (typeof fun === 'function' && !!fun.creator) {
    1277                         e = this.line;
    1278
    1279                         // creator methods are the only ones that take properties, hence this special case
    1280                         try {
    1281                             ret = fun(parents, attr);
    1282                             ret.jcLineStart = e;
    1283                             ret.jcLineEnd = node.eline;
    1284
    1285                             for (i = e; i <= node.line; i++) {
    1286                                 this.lineToElement[i] = ret;
    1287                             }
    1288
    1289                             ret.debugParents = this.dpstack[this.pscope];
    1290                         } catch (ex) {
    1291                             this._error(ex.toString());
    1292                         }
    1293                     } else {
    1294                         this._error('Function \'' + fun + '\' is undefined.');
    1295                     }
    1296
    1297                     // clear parameter stack
    1298                     this.dpstack.pop();
    1299                     this.pscope--;
    1300                     break;
    1301                 case 'op_property':
    1302                     e = this.execute(node.children[0]);
    1303                     v = node.children[1];
    1304
    1305                     ret = this.resolveProperty(e, v, false);
    1306
    1307                     // set the scope, in case this is a method the user wants to call
    1308                     if (Type.exists(ret)) {
    1309                         ret.sc = e;
    1310                     }
    1311
    1312                     break;
    1313                 case 'op_use':
    1314                     this._warn('Use of the \'use\' operator is deprecated.');
    1315                     this.use(node.children[0].toString());
    1316                     break;
    1317                 case 'op_delete':
    1318                     this._warn('Use of the \'delete\' operator is deprecated. Please use the remove() function.');
    1319                     v = this.getvar(node.children[0]);
    1320                     ret = this.del(v);
    1321                     break;
    1322                 case 'op_equ':
    1323                     // == is intentional
    1324                     /*jslint eqeq:true*/
    1325                     ret = this.execute(node.children[0]) == this.execute(node.children[1]);
    1326                     /*jslint eqeq:false*/
    1327                     break;
    1328                 case 'op_neq':
    1329                     // != is intentional
    1330                     /*jslint eqeq:true*/
    1331                     ret = this.execute(node.children[0]) != this.execute(node.children[1]);
    1332                     /*jslint eqeq:true*/
    1333                     break;
    1334                 case 'op_approx':
    1335                     ret = Math.abs(this.execute(node.children[0]) - this.execute(node.children[1])) < Mat.eps;
    1336                     break;
    1337                 case 'op_grt':
    1338                     ret = this.execute(node.children[0]) > this.execute(node.children[1]);
    1339                     break;
    1340                 case 'op_lot':
    1341                     ret = this.execute(node.children[0]) < this.execute(node.children[1]);
    1342                     break;
    1343                 case 'op_gre':
    1344                     ret = this.execute(node.children[0]) >= this.execute(node.children[1]);
    1345                     break;
    1346                 case 'op_loe':
    1347                     ret = this.execute(node.children[0]) <= this.execute(node.children[1]);
    1348                     break;
    1349                 case 'op_or':
    1350                     ret = this.execute(node.children[0]) || this.execute(node.children[1]);
    1351                     break;
    1352                 case 'op_and':
    1353                     ret = this.execute(node.children[0]) && this.execute(node.children[1]);
    1354                     break;
    1355                 case 'op_not':
    1356                     ret = !this.execute(node.children[0]);
    1357                     break;
    1358                 case 'op_add':
    1359                     ret = this.add(this.execute(node.children[0]), this.execute(node.children[1]));
    1360                     break;
    1361                 case 'op_sub':
    1362                     ret = this.sub(this.execute(node.children[0]), this.execute(node.children[1]));
    1363                     break;
    1364                 case 'op_div':
    1365                     ret = this.div(this.execute(node.children[0]), this.execute(node.children[1]));
    1366                     break;
    1367                 case 'op_mod':
    1368                     // use mathematical modulo, JavaScript implements the symmetric modulo.
    1369                     ret = this.mod(this.execute(node.children[0]), this.execute(node.children[1]), true);
    1370                     break;
    1371                 case 'op_mul':
    1372                     ret = this.mul(this.execute(node.children[0]), this.execute(node.children[1]));
    1373                     break;
    1374                 case 'op_exp':
    1375                     ret = this.pow(this.execute(node.children[0]),  this.execute(node.children[1]));
    1376                     break;
    1377                 case 'op_neg':
    1378                     ret = this.neg(this.execute(node.children[0]));
    1379                     break;
    1380                 }
    1381                 break;
    1382
    1383             case 'node_var':
    1384                 ret = this.getvar(node.value);
    1385                 break;
    1386
    1387             case 'node_const':
    1388                 ret = Number(node.value);
    1389                 break;
    1390
    1391             case 'node_const_bool':
    1392                 ret = node.value;
    1393                 break;
    1394
    1395             case 'node_str':
    1396                 //ret = node.value.replace(/\\'/, "'").replace(/\\"/, '"').replace(/\\\\/, '\\');
    1397                 /*jslint regexp:true*/
    1398                 ret = node.value.replace(/\\(.)/, '$1');
    1399                 /*jslint regexp:false*/
    1400                 break;
    1401             }
    1402
    1403             return ret;
    1404         },
    1405
    1406         /**
    1407          * Compiles a parse tree back to JessieCode.
    1408          * @param {Object} node
    1409          * @param {Boolean} [js=false] Compile either to JavaScript or back to JessieCode (required for the UI).
    1410          * @returns Something
    1411          * @private
    1412          */
    1413         compile: function (node, js) {
    1414             var e, i, list, scope,
    1415                 ret = '';
    1416
    1417             if (!Type.exists(js)) {
    1418                 js = false;
    1419             }
    1420
    1421             if (!node) {
    1422                 return ret;
    1423             }
    1424
    1425             switch (node.type) {
    1426             case 'node_op':
    1427                 switch (node.value) {
    1428                 case 'op_none':
    1429                     if (node.children[0]) {
    1430                         ret = this.compile(node.children[0], js);
    1431                     }
    1432                     if (node.children[1]) {
    1433                         ret += this.compile(node.children[1], js);
    1434                     }
    1435                     break;
    1436                 case 'op_assign':
    1437                     //e = this.compile(node.children[0], js);
    1438                     if (js) {
    1439                         e = this.getLHSCompiler(node.children[0], js);
    1440                         if (Type.isArray(e)) {
    1441                             ret = '$jc$.setProp(' + e[0] + ', ' + e[1] + ', ' + this.compile(node.children[1], js) + ');\n';
    1442                         } else {
    1443                             if (this.isLocalVariable(e) !== this.scope) {
    1444                                 this.scope.locals[e] = true;
    1445                             }
    1446                             ret = '$jc$.scopes[' + this.scope.id + '].locals[\'' + e + '\'] = ' + this.compile(node.children[1], js) + ';\n';
    1447                         }
    1448                     } else {
    1449                         e = this.compile(node.children[0]);
    1450                         ret = e + ' = ' + this.compile(node.children[1], js) + ';\n';
    1451                     }
    1452                     break;
    1453                 case 'op_if':
    1454                     ret = ' if (' + this.compile(node.children[0], js) + ') ' + this.compile(node.children[1], js);
    1455                     break;
    1456                 case 'op_if_else':
    1457                     ret = ' if (' + this.compile(node.children[0], js) + ')' + this.compile(node.children[1], js);
    1458                     ret += ' else ' + this.compile(node.children[2], js);
    1459                     break;
    1460                 case 'op_conditional':
    1461                     ret = '((' + this.compile(node.children[0], js) + ')?(' + this.compile(node.children[1], js);
    1462                     ret += '):(' + this.compile(node.children[2], js) + '))';
    1463                     break;
    1464                 case 'op_while':
    1465                     ret = ' while (' + this.compile(node.children[0], js) + ') {\n' + this.compile(node.children[1], js) + '}\n';
    1466                     break;
    1467                 case 'op_do':
    1468                     ret = ' do {\n' + this.compile(node.children[0], js) + '} while (' + this.compile(node.children[1], js) + ');\n';
    1469                     break;
    1470                 case 'op_for':
    1471                     ret = ' for (' + this.compile(node.children[0], js) + '; ' + this.compile(node.children[1], js) + '; ' + this.compile(node.children[2], js) + ') {\n' + this.compile(node.children[3], js) + '\n}\n';
    1472                     break;
    1473                 case 'op_proplst':
    1474                     if (node.children[0]) {
    1475                         ret = this.compile(node.children[0], js) + ', ';
    1476                     }
    1477
    1478                     ret += this.compile(node.children[1], js);
    1479                     break;
    1480                 case 'op_prop':
    1481                     // child 0: Identifier
    1482                     // child 1: Value
    1483                     ret = node.children[0] + ': ' + this.compile(node.children[1], js);
    1484                     break;
    1485                 case 'op_emptyobject':
    1486                     ret = js ? '{}' : '<< >>';
    1487                     break;
    1488                 case 'op_proplst_val':
    1489                     ret = this.compile(node.children[0], js);
    1490                     break;
    1491                 case 'op_array':
    1492                     list = [];
    1493                     for (i = 0; i < node.children[0].length; i++) {
    1494                         list.push(this.compile(node.children[0][i], js));
    1495                     }
    1496                     ret = '[' + list.join(', ') + ']';
    1497                     break;
    1498                 case 'op_extvalue':
    1499                     ret = this.compile(node.children[0], js) + '[' + this.compile(node.children[1], js) + ']';
    1500                     break;
    1501                 case 'op_return':
    1502                     ret = ' return ' + this.compile(node.children[0], js) + ';\n';
    1503                     break;
    1504                 case 'op_map':
    1505                     if (!node.children[1].isMath && node.children[1].type !== 'node_var') {
    1506                         this._error('compile: In a map only function calls and mathematical expressions are allowed.');
    1507                     }
    1508
    1509                     list = node.children[0];
    1510                     if (js) {
    1511                         ret = ' $jc$.makeMap(function (' + list.join(', ') + ') { return ' + this.compile(node.children[1], js) + '; })';
    1512                     } else {
    1513                         ret = 'map (' + list.join(', ') + ') -> ' + this.compile(node.children[1], js);
    1514                     }
    1515
    1516                     break;
    1517                 case 'op_function':
    1518                     list = node.children[0];
    1519                     scope = this.pushScope(list);
    1520                     if (js) {
    1521                         ret = this.functionCodeJS(node);
    1522                     } else {
    1523                         ret = ' function (' + list.join(', ') + ') ' + this.compile(node.children[1], js);
    1524                     }
    1525                     this.popScope();
    1526                     break;
    1527                 case 'op_execfunmath':
    1528                     console.log('TODO');
    1529                     ret = '-1';
    1530                     break;
    1531                 case 'op_execfun':
    1532                     // parse the properties only if given
    1533                     if (node.children[2]) {
    1534                         list = [];
    1535                         for (i = 0; i < node.children[2].length; i++) {
    1536                             list.push(this.compile(node.children[2][i], js));
    1537                         }
    1538
    1539                         if (js) {
    1540                             e = '$jc$.mergeAttributes(' + list.join(', ') + ')';
    1541                         }
    1542                     }
    1543                     node.children[0].withProps = !!node.children[2];
    1544                     list = [];
    1545                     for (i = 0; i < node.children[1].length; i++) {
    1546                         list.push(this.compile(node.children[1][i], js));
    1547                     }
    1548                     ret = this.compile(node.children[0], js) + '(' + list.join(', ') + (node.children[2] && js ? ', ' + e : '') + ')' + (node.children[2] && !js ? e : '');
    1549
    1550                     // save us a function call when compiled to javascript
    1551                     if (js && node.children[0].value === '$') {
    1552                         ret = '$jc$.board.objects[' + this.compile(node.children[1][0], js) + ']';
    1553                     }
    1554                     break;
    1555                 case 'op_property':
    1556                     if (js && node.children[1] !== 'X' && node.children[1] !== 'Y') {
    1557                         ret = '$jc$.resolveProperty(' + this.compile(node.children[0], js) + ', \'' + node.children[1] + '\', true)';
    1558                     } else {
    1559                         ret = this.compile(node.children[0], js) + '.' + node.children[1];
    1560                     }
    1561                     break;
    1562                 case 'op_use':
    1563                     this._warn('Use of the \'use\' operator is deprecated.');
    1564                     if (js) {
    1565                         ret = '$jc$.use(\'';
    1566                     } else {
    1567                         ret = 'use(\'';
    1568                     }
    1569
    1570                     ret += node.children[0].toString() + '\');';
    1571                     break;
    1572                 case 'op_delete':
    1573                     this._warn('Use of the \'delete\' operator is deprecated. Please use the remove() function.');
    1574                     if (js) {
    1575                         ret = '$jc$.del(';
    1576                     } else {
    1577                         ret = 'remove(';
    1578                     }
    1579
    1580                     ret += this.compile(node.children[0], js) + ')';
    1581                     break;
    1582                 case 'op_equ':
    1583                     ret = '(' + this.compile(node.children[0], js) + ' == ' + this.compile(node.children[1], js) + ')';
    1584                     break;
    1585                 case 'op_neq':
    1586                     ret = '(' + this.compile(node.children[0], js) + ' != ' + this.compile(node.children[1], js) + ')';
    1587                     break;
    1588                 case 'op_approx':
    1589                     ret = '(' + this.compile(node.children[0], js) + ' ~= ' + this.compile(node.children[1], js) + ')';
    1590                     break;
    1591                 case 'op_grt':
    1592                     ret = '(' + this.compile(node.children[0], js) + ' > ' + this.compile(node.children[1], js) + ')';
    1593                     break;
    1594                 case 'op_lot':
    1595                     ret = '(' + this.compile(node.children[0], js) + ' < ' + this.compile(node.children[1], js) + ')';
    1596                     break;
    1597                 case 'op_gre':
    1598                     ret = '(' + this.compile(node.children[0], js) + ' >= ' + this.compile(node.children[1], js) + ')';
    1599                     break;
    1600                 case 'op_loe':
    1601                     ret = '(' + this.compile(node.children[0], js) + ' <= ' + this.compile(node.children[1], js) + ')';
    1602                     break;
    1603                 case 'op_or':
    1604                     ret = '(' + this.compile(node.children[0], js) + ' || ' + this.compile(node.children[1], js) + ')';
    1605                     break;
    1606                 case 'op_and':
    1607                     ret = '(' + this.compile(node.children[0], js) + ' && ' + this.compile(node.children[1], js) + ')';
    1608                     break;
    1609                 case 'op_not':
    1610                     ret = '!(' + this.compile(node.children[0], js) + ')';
    1611                     break;
    1612                 case 'op_add':
    1613                     if (js) {
    1614                         ret = '$jc$.add(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
    1615                     } else {
    1616                         ret = '(' + this.compile(node.children[0], js) + ' + ' + this.compile(node.children[1], js) + ')';
    1617                     }
    1618                     break;
    1619                 case 'op_sub':
    1620                     if (js) {
    1621                         ret = '$jc$.sub(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
    1622                     } else {
    1623                         ret = '(' + this.compile(node.children[0], js) + ' - ' + this.compile(node.children[1], js) + ')';
    1624                     }
    1625                     break;
    1626                 case 'op_div':
    1627                     if (js) {
    1628                         ret = '$jc$.div(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
    1629                     } else {
    1630                         ret = '(' + this.compile(node.children[0], js) + ' / ' + this.compile(node.children[1], js) + ')';
    1631                     }
    1632                     break;
    1633                 case 'op_mod':
    1634                     if (js) {
    1635                         ret = '$jc$.mod(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ', true)';
    1636                     } else {
    1637                         ret = '(' + this.compile(node.children[0], js) + ' % ' + this.compile(node.children[1], js) + ')';
    1638                     }
    1639                     break;
    1640                 case 'op_mul':
    1641                     if (js) {
    1642                         ret = '$jc$.mul(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
    1643                     } else {
    1644                         ret = '(' + this.compile(node.children[0], js) + ' * ' + this.compile(node.children[1], js) + ')';
    1645                     }
    1646                     break;
    1647                 case 'op_exp':
    1648                     if (js) {
    1649                         ret = '$jc$.pow(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
    1650                     } else {
    1651                         ret = '(' + this.compile(node.children[0], js) + '^' + this.compile(node.children[1], js) + ')';
    1652                     }
    1653                     break;
    1654                 case 'op_neg':
    1655                     if (js) {
    1656                         ret = '$jc$.neg(' + this.compile(node.children[0], js) + ')';
    1657                     } else {
    1658                         ret = '(-' + this.compile(node.children[0], js) + ')';
    1659                     }
    1660                     break;
    1661                 }
    1662                 break;
    1663
    1664             case 'node_var':
    1665                 if (js) {
    1666                     ret = this.getvarJS(node.value, false, node.withProps);
    1667                 } else {
    1668                     ret = node.value;
    1669                 }
    1670                 break;
    1671
    1672             case 'node_const':
    1673                 ret = node.value;
    1674                 break;
    1675
    1676             case 'node_const_bool':
    1677                 ret = node.value;
    1678                 break;
    1679
    1680             case 'node_str':
    1681                 ret = '\'' + node.value + '\'';
    1682                 break;
    1683             }
    1684
    1685             if (node.needsBrackets) {
    1686                 ret = '{\n' + ret + '}\n';
    1687             }
    1688
    1689             return ret;
    1690         },
    1691
    1692         /**
    1693          * This is used as the global X() function.
    1694          * @param {JXG.Point|JXG.Text} e
    1695          * @returns {Number}
    1696          */
    1697         X: function (e) {
    1698             return e.X();
    1699         },
    1700
    1701         /**
    1702          * This is used as the global Y() function.
    1703          * @param {JXG.Point|JXG.Text} e
    1704          * @returns {Number}
    1705          */
    1706         Y: function (e) {
    1707             return e.Y();
    1708         },
    1709
    1710         /**
    1711          * This is used as the global V() function.
    1712          * @param {Glider|Slider} e
    1713          * @returns {Number}
    1714          */
    1715         V: function (e) {
    1716             return e.Value();
    1717         },
    1718
    1719         /**
    1720          * This is used as the global L() function.
    1721          * @param {JXG.Line} e
    1722          * @returns {Number}
    1723          */
    1724         L: function (e) {
    1725             return e.L();
    1726         },
    1727
    1728         /**
    1729          * This is used as the global dist() function.
    1730          * @param {JXG.Point} p1
    1731          * @param {JXG.Point} p2
    1732          * @returns {Number}
    1733          */
    1734         dist: function (p1, p2) {
    1735             if (!Type.exists(p1) || !Type.exists(p1.Dist)) {
    1736                 this._error('Error: Can\'t calculate distance.');
    1737             }
    1738
    1739             return p1.Dist(p2);
    1740         },
    1741
    1742         /**
    1743          * + operator implementation
    1744          * @param {Number|Array|JXG.Point} a
    1745          * @param {Number|Array|JXG.Point} b
    1746          * @returns {Number|Array}
    1747          */
    1748         add: function (a, b) {
    1749             var i, len, res;
    1750
    1751             a = Type.evalSlider(a);
    1752             b = Type.evalSlider(b);
    1753
    1754             if (Type.isArray(a) && Type.isArray(b)) {
    1755                 len = Math.min(a.length, b.length);
    1756                 res = [];
    1757
    1758                 for (i = 0; i < len; i++) {
    1759                     res[i] = a[i] + b[i];
    1760                 }
    1761             } else if (Type.isNumber(a) && Type.isNumber(b)) {
    1762                 res = a + b;
    1763             } else if (Type.isString(a) || Type.isString(b)) {
    1764                 res = a.toString() + b.toString();
    1765             } else {
    1766                 this._error('Operation + not defined on operands ' + typeof a + ' and ' + typeof b);
    1767             }
    1768
    1769             return res;
    1770         },
    1771
    1772         /**
    1773          * - operator implementation
    1774          * @param {Number|Array|JXG.Point} a
    1775          * @param {Number|Array|JXG.Point} b
    1776          * @returns {Number|Array}
    1777          */
    1778         sub: function (a, b) {
    1779             var i, len, res;
    1780
    1781             a = Type.evalSlider(a);
    1782             b = Type.evalSlider(b);
    1783
    1784             if (Type.isArray(a) && Type.isArray(b)) {
    1785                 len = Math.min(a.length, b.length);
    1786                 res = [];
    1787
    1788                 for (i = 0; i < len; i++) {
    1789                     res[i] = a[i] - b[i];
    1790                 }
    1791             } else if (Type.isNumber(a) && Type.isNumber(b)) {
    1792                 res = a - b;
    1793             } else {
    1794                 this._error('Operation - not defined on operands ' + typeof a + ' and ' + typeof b);
    1795             }
    1796
    1797             return res;
    1798         },
    1799
    1800         /**
    1801          * unary - operator implementation
    1802          * @param {Number|Array|JXG.Point} a
    1803          * @returns {Number|Array}
    1804          */
    1805         neg: function (a) {
    1806             var i, len, res;
    1807
    1808             a = Type.evalSlider(a);
    1809
    1810             if (Type.isArray(a)) {
    1811                 len = a.length;
    1812                 res = [];
    1813
    1814                 for (i = 0; i < len; i++) {
    1815                     res[i] = -a[i];
    1816                 }
    1817             } else if (Type.isNumber(a)) {
    1818                 res = -a;
    1819             } else {
    1820                 this._error('Unary operation - not defined on operand ' + typeof a);
    1821             }
    1822
    1823             return res;
    1824         },
    1825
    1826
    1827         /**
    1828          * Multiplication of vectors and numbers
    1829          * @param {Number|Array} a
    1830          * @param {Number|Array} b
    1831          * @returns {Number|Array} (Inner) product of the given input values.
    1832          */
    1833         mul: function (a, b) {
    1834             var i, len, res;
    1835
    1836             a = Type.evalSlider(a);
    1837             b = Type.evalSlider(b);
    1838
    1839             if (Type.isArray(a) && Type.isNumber(b)) {
    1840                 // swap b and a
    1841                 i = a;
    1842                 a = b;
    1843                 b = a;
    1844             }
    1845
    1846             if (Type.isArray(a) && Type.isArray(b)) {
    1847                 len = Math.min(a.length, b.length);
    1848                 res = Mat.innerProduct(a, b, len);
    1849             } else if (Type.isNumber(a) && Type.isArray(b)) {
    1850                 len = b.length;
    1851                 res = [];
    1852
    1853                 for (i = 0; i < len; i++) {
    1854                     res[i] = a * b[i];
    1855                 }
    1856             } else if (Type.isNumber(a) && Type.isNumber(b)) {
    1857                 res = a * b;
    1858             } else {
    1859                 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);
    1860             }
    1861
    1862             return res;
    1863         },
    1864
    1865         /**
    1866          * Implementation of the / operator.
    1867          * @param {Number|Array} a
    1868          * @param {Number} b
    1869          * @returns {Number|Array}
    1870          */
    1871         div: function (a, b) {
    1872             var i, len, res;
    1873
    1874             a = Type.evalSlider(a);
    1875             b = Type.evalSlider(b);
    1876
    1877             if (Type.isArray(a) && Type.isNumber(b)) {
    1878                 len = a.length;
    1879                 res = [];
    1880
    1881                 for (i = 0; i < len; i++) {
    1882                     res[i] = a[i] / b;
    1883                 }
    1884             } else if (Type.isNumber(a) && Type.isNumber(b)) {
    1885                 res = a / b;
    1886             } else {
    1887                 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);
    1888             }
    1889
    1890             return res;
    1891         },
    1892
    1893         /**
    1894          * Implementation of the % operator.
    1895          * @param {Number|Array} a
    1896          * @param {Number} b
    1897          * @returns {Number|Array}
    1898          */
    1899         mod: function (a, b) {
    1900             var i, len, res;
    1901
    1902             a = Type.evalSlider(a);
    1903             b = Type.evalSlider(b);
    1904
    1905             if (Type.isArray(a) && Type.isNumber(b)) {
    1906                 len = a.length;
    1907                 res = [];
    1908
    1909                 for (i = 0; i < len; i++) {
    1910                     res[i] = Mat.mod(a[i], b, true);
    1911                 }
    1912             } else if (Type.isNumber(a) && Type.isNumber(b)) {
    1913                 res = Mat.mod(a, b, true);
    1914             } else {
    1915                 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);
    1916             }
    1917
    1918             return res;
    1919         },
    1920
    1921         /**
    1922          * Pow function wrapper to allow direct usage of sliders.
    1923          * @param {Number|Slider} a
    1924          * @param {Number|Slider} b
    1925          * @returns {Number}
    1926          */
    1927         pow: function (a, b) {
    1928             a = Type.evalSlider(a);
    1929             b = Type.evalSlider(b);
    1930
    1931             return Math.pow(a, b);
    1932         },
    1933
    1934         DDD: function(f) {
    1935             console.log('Dummy derivative function. This should never appear!');
    1936         },
    1937
    1938         /**
    1939          * Implementation of the ?: operator
    1940          * @param {Boolean} cond Condition
    1941          * @param {*} v1
    1942          * @param {*} v2
    1943          * @returns {*} Either v1 or v2.
    1944          */
    1945         ifthen: function (cond, v1, v2) {
    1946             if (cond) {
    1947                 return v1;
    1948             }
    1949
    1950             return v2;
    1951         },
    1952
    1953         /**
    1954          * Implementation of the delete() builtin function
    1955          * @param {JXG.GeometryElement} element
    1956          */
    1957         del: function (element) {
    1958             if (typeof element === 'object' && JXG.exists(element.type) && JXG.exists(element.elementClass)) {
    1959                 this.board.removeObject(element);
    1960             }
    1961         },
    1962
    1963         /**
    1964          * Implementation of the use() builtin function
    1965          * @param {String} board
    1966          */
    1967         use: function (board) {
    1968             var b, ref,
    1969                 found = false;
    1970
    1971             if (typeof board === 'string') {
    1972                 // search all the boards for the one with the appropriate container div
    1973                 for (b in JXG.boards) {
    1974                     if (JXG.boards.hasOwnProperty(b) && JXG.boards[b].container === board) {
    1975                         ref = JXG.boards[b];
    1976                         found = true;
    1977                         break;
    1978                     }
    1979                 }
    1980             } else {
    1981                 ref = board;
    1982                 found = true;
    1983             }
    1984
    1985             if (found) {
    1986                 this.board = ref;
    1987                 this.builtIn.$board = ref;
    1988                 this.builtIn.$board.src = '$jc$.board';
    1989             } else {
    1990                 this._error('Board \'' + board + '\' not found!');
    1991             }
    1992         },
    1993
    1994         /**
    1995          * Find the first symbol to the given value from the given scope upwards.
    1996          * @param v Value
    1997          * @param {Number} [scope=-1] The scope, default is to start with current scope (-1).
    1998          * @returns {Array} An array containing the symbol and the scope if a symbol could be found,
    1999          * an empty array otherwise;
    2000          */
    2001         findSymbol: function (v, scope) {
    2002             var i, s;
    2003
    2004             scope = Type.def(scope, -1);
    2005
    2006             if (scope === -1) {
    2007                 s = this.scope;
    2008             } else {
    2009                 s = this.scopes[scope];
    2010             }
    2011
    2012             while (s !== null) {
    2013                 for (i in s.locals) {
    2014                     if (s.locals.hasOwnProperty(i) && s.locals[i] === v) {
    2015                         return [i, s];
    2016                     }
    2017                 }
    2018
    2019                 s = s.previous;
    2020             }
    2021
    2022             return [];
    2023         },
    2024
    2025         /**
    2026          * Import modules into a JessieCode script.
    2027          * @param {String} module
    2028          */
    2029         importModule: function (module) {
    2030             return priv.modules[module.toLowerCase()];
    2031         },
    2032
    2033         /**
    2034          * Defines built in methods and constants.
    2035          * @returns {Object} BuiltIn control object
    2036          */
    2037         defineBuiltIn: function () {
    2038             var that = this,
    2039                 builtIn = {
    2040                     PI: Math.PI,
    2041                     EULER: Math.E,
    2042                     X: that.X,
    2043                     Y: that.Y,
    2044                     V: that.V,
    2045                     L: that.L,
    2046                     dist: that.dist,
    2047                     rad: Geometry.rad,
    2048                     deg: Geometry.trueAngle,
    2049                     factorial: Mat.factorial,
    2050                     trunc: Type.trunc,
    2051                     log: Mat.log,
    2052                     ln: Math.log,
    2053                     log10: Mat.log10,
    2054                     lg: Mat.log10,
    2055                     log2: Mat.log2,
    2056                     lb: Mat.log2,
    2057                     ld: Mat.log2,
    2058                     cosh: Mat.cosh,
    2059                     sinh: Mat.sinh,
    2060                     IfThen: that.ifthen,
    2061                     'import': that.importModule,
    2062                     'use': that.use,
    2063                     'remove': that.del,
    2064                     '$': that.getElementById,
    2065                     '$board': that.board,
    2066                     '$log': that.log,
    2067                     D: that.DDD
    2068                 };
    2069
    2070             // special scopes for factorial, deg, and rad
    2071             builtIn.rad.sc = Geometry;
    2072             builtIn.deg.sc = Geometry;
    2073             builtIn.factorial.sc = Mat;
    2074
    2075             // set the javascript equivalent for the builtIns
    2076             // some of the anonymous functions should be replaced by global methods later on
    2077             // EULER and PI don't get a source attribute - they will be lost anyways and apparently
    2078             // some browser will throw an exception when a property is assigned to a primitive value.
    2079             builtIn.X.src = '$jc$.X';
    2080             builtIn.Y.src = '$jc$.Y';
    2081             builtIn.V.src = '$jc$.V';
    2082             builtIn.L.src = '$jc$.L';
    2083             builtIn.dist.src = '$jc$.dist';
    2084             builtIn.rad.src = 'JXG.Math.Geometry.rad';
    2085             builtIn.deg.src = 'JXG.Math.Geometry.trueAngle';
    2086             builtIn.factorial.src = 'JXG.Math.factorial';
    2087             builtIn.trunc.src = 'JXG.trunc';
    2088             builtIn.ln.src = 'Math.log';
    2089             builtIn.log10.src = 'JXG.Math.log10';
    2090             builtIn.lg.src = 'JXG.Math.log10';
    2091             builtIn.log2.src = 'JXG.Math.log2';
    2092             builtIn.lb.src = 'JXG.Math.log2';
    2093             builtIn.ld.src = 'JXG.Math.log2';
    2094             builtIn.cosh.src = 'JXG.Math.cosh';
    2095             builtIn.sinh.src = 'JXG.Math.sinh';
    2096             builtIn['import'].src = '$jc$.importModule';
    2097             builtIn.use.src = '$jc$.use';
    2098             builtIn.remove.src = '$jc$.del';
    2099             builtIn.IfThen.src = '$jc$.ifthen';
    2100             // usually unused, see node_op > op_execfun
    2101             builtIn.$.src = '(function (n) { return $jc$.board.select(n); })';
    2102             if (builtIn.$board) {
    2103                 builtIn.$board.src = '$jc$.board';
    2104             }
    2105             builtIn.$log.src = '$jc$.log';
    2106
    2107             return builtIn;
    2108         },
    2109
    2110         /**
    2111          * Output a debugging message. Uses debug console, if available. Otherwise an HTML element with the
    2112          * id "debug" and an innerHTML property is used.
    2113          * @param {String} log
    2114          * @private
    2115          */
    2116         _debug: function (log) {
    2117             if (typeof console === 'object') {
    2118                 console.log(log);
    2119             } else if (Env.isBrowser && document && document.getElementById('debug') !== null) {
    2120                 document.getElementById('debug').innerHTML += log + '<br />';
    2121             }
    2122         },
    2123
    2124         /**
    2125          * Throws an exception with the given error message.
    2126          * @param {String} msg Error message
    2127          */
    2128         _error: function (msg) {
    2129             var e = new Error('Error(' + this.line + '): ' + msg);
    2130             e.line = this.line;
    2131             throw e;
    2132         },
    2133
    2134         /**
    2135          * Output a warning message using {@link JXG#debug} and precedes the message with "Warning: ".
    2136          * @param {String} msg
    2137          */
    2138         _warn: function (msg) {
    2139             if (typeof console === 'object') {
    2140                 console.log('Warning(' + this.line + '): ' + msg);
    2141             } else if (Env.isBrowser && document && document.getElementById(this.warnLog) !== null) {
    2142                 document.getElementById(this.warnLog).innerHTML += 'Warning(' + this.line + '): ' + msg + '<br />';
    2143             }
    2144         },
    2145
    2146         _log: function (msg) {
    2147             if (typeof window !== 'object' && typeof self === 'object' && self.postMessage) {
    2148                 self.postMessage({type: 'log', msg: 'Log: ' + msg.toString()});
    2149             } else {
    2150                 console.log('Log: ', arguments);
    2151             }
    2152         }
    2153
    2154     });
    2155
    2156 /* parser generated by jison 0.4.17 */
    2157 /*
    2158   Returns a Parser object of the following structure:
    2159
    2160   Parser: {
    2161     yy: {}
    2162   }
    2163
    2164   Parser.prototype: {
    2165     yy: {},
    2166     trace: function(),
    2167     symbols_: {associative list: name ==> number},
    2168     terminals_: {associative list: number ==> name},
    2169     productions_: [...],
    2170     performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
    2171     table: [...],
    2172     defaultActions: {...},
    2173     parseError: function(str, hash),
    2174     parse: function(input),
    2175
    2176     lexer: {
    2177         EOF: 1,
    2178         parseError: function(str, hash),
    2179         setInput: function(input),
    2180         input: function(),
    2181         unput: function(str),
    2182         more: function(),
    2183         less: function(n),
    2184         pastInput: function(),
    2185         upcomingInput: function(),
    2186         showPosition: function(),
    2187         test_match: function(regex_match_array, rule_index),
    2188         next: function(),
    2189         lex: function(),
    2190         begin: function(condition),
    2191         popState: function(),
    2192         _currentRules: function(),
    2193         topState: function(),
    2194         pushState: function(condition),
    2195
    2196         options: {
    2197             ranges: boolean           (optional: true ==> token location info will include a .range[] member)
    2198             flex: boolean             (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
    2199             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)
    2200         },
    2201
    2202         performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
    2203         rules: [...],
    2204         conditions: {associative list: name ==> set},
    2205     }
    2206   }
    2207
    2208
    2209   token location info (@$, _$, etc.): {
    2210     first_line: n,
    2211     last_line: n,
    2212     first_column: n,
    2213     last_column: n,
    2214     range: [start_number, end_number]       (where the numbers are indexes into the input string, regular zero-based)
    2215   }
    2216
    2217
    2218   the parseError function receives a 'hash' object with these members for lexer and parser errors: {
    2219     text:        (matched text)
    2220     token:       (the produced terminal token, if any)
    2221     line:        (yylineno)
    2222   }
    2223   while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
    2224     loc:         (yylloc)
    2225     expected:    (string describing the set of expected tokens)
    2226     recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
    2227   }
    2228 */
    2229 var parser = (function(){
    2230 var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,14],$V1=[1,13],$V2=[1,37],$V3=[1,14],$V4=[1,15],$V5=[1,21],$V6=[1,16],$V7=[1,17],$V8=[1,33],$V9=[1,18],$Va=[1,19],$Vb=[1,12],$Vc=[1,59],$Vd=[1,60],$Ve=[1,58],$Vf=[1,46],$Vg=[1,48],$Vh=[1,49],$Vi=[1,50],$Vj=[1,51],$Vk=[1,52],$Vl=[1,53],$Vm=[1,54],$Vn=[1,45],$Vo=[1,38],$Vp=[1,39],$Vq=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vr=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vs=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vt=[2,48],$Vu=[1,72],$Vv=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],$Vw=[1,78],$Vx=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vy=[1,82],$Vz=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$VA=[1,83],$VB=[1,84],$VC=[1,85],$VD=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],$VE=[1,89],$VF=[1,90],$VG=[1,91],$VH=[1,92],$VI=[1,97],$VJ=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$VK=[1,103],$VL=[1,104],$VM=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],$VN=[1,105],$VO=[1,106],$VP=[1,107],$VQ=[1,126],$VR=[1,139],$VS=[83,86],$VT=[1,149],$VU=[10,66,86],$VV=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],$VW=[1,166],$VX=[10,86];
    2231 var parser = {trace: function trace() { },
    2232 yy: {},
    2233 symbols_: {"error":2,"Program":3,"StatementList":4,"EOF":5,"IfStatement":6,"IF":7,"(":8,"Expression":9,")":10,"Statement":11,"ELSE":12,"LoopStatement":13,"WHILE":14,"FOR":15,";":16,"DO":17,"UnaryStatement":18,"USE":19,"IDENTIFIER":20,"DELETE":21,"ReturnStatement":22,"RETURN":23,"EmptyStatement":24,"StatementBlock":25,"{":26,"}":27,"ExpressionStatement":28,"AssignmentExpression":29,"ConditionalExpression":30,"LeftHandSideExpression":31,"=":32,"LogicalORExpression":33,"?":34,":":35,"LogicalANDExpression":36,"||":37,"EqualityExpression":38,"&&":39,"RelationalExpression":40,"==":41,"!=":42,"~=":43,"AdditiveExpression":44,"<":45,">":46,"<=":47,">=":48,"MultiplicativeExpression":49,"+":50,"-":51,"UnaryExpression":52,"*":53,"/":54,"%":55,"ExponentExpression":56,"^":57,"!":58,"MemberExpression":59,"CallExpression":60,"PrimaryExpression":61,"FunctionExpression":62,"MapExpression":63,".":64,"[":65,"]":66,"BasicLiteral":67,"ObjectLiteral":68,"ArrayLiteral":69,"NullLiteral":70,"BooleanLiteral":71,"StringLiteral":72,"NumberLiteral":73,"NULL":74,"TRUE":75,"FALSE":76,"STRING":77,"NUMBER":78,"NAN":79,"INFINITY":80,"ElementList":81,"<<":82,">>":83,"PropertyList":84,"Property":85,",":86,"PropertyName":87,"Arguments":88,"AttributeList":89,"Attribute":90,"FUNCTION":91,"ParameterDefinitionList":92,"MAP":93,"->":94,"$accept":0,"$end":1},
    2234 terminals_: {2:"error",5:"EOF",7:"IF",8:"(",10:")",12:"ELSE",14:"WHILE",15:"FOR",16:";",17:"DO",19:"USE",20:"IDENTIFIER",21:"DELETE",23:"RETURN",26:"{",27:"}",32:"=",34:"?",35:":",37:"||",39:"&&",41:"==",42:"!=",43:"~=",45:"<",46:">",47:"<=",48:">=",50:"+",51:"-",53:"*",54:"/",55:"%",57:"^",58:"!",64:".",65:"[",66:"]",74:"NULL",75:"TRUE",76:"FALSE",77:"STRING",78:"NUMBER",79:"NAN",80:"INFINITY",82:"<<",83:">>",86:",",91:"FUNCTION",93:"MAP",94:"->"},
    2235 productions_: [0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,6],[92,1],[92,3]],
    2236 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
    2237 /* this == yyval */
    2238
    2239 var $0 = $$.length - 1;
    2240 switch (yystate) {
    2241 case 1:
    2242  return $$[$0-1];
    2243 break;
    2244 case 2:
    2245  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_if', $$[$0-2], $$[$0]);
    2246 break;
    2247 case 3:
    2248  this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_if_else', $$[$0-4], $$[$0-2], $$[$0]);
    2249 break;
    2250 case 4:
    2251  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_while', $$[$0-2], $$[$0]);
    2252 break;
    2253 case 5:
    2254  this.$ = AST.createNode(lc(_$[$0-8]), 'node_op', 'op_for', $$[$0-6], $$[$0-4], $$[$0-2], $$[$0]);
    2255 break;
    2256 case 6:
    2257  this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_do', $$[$0-5], $$[$0-2]);
    2258 break;
    2259 case 7:
    2260  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_use', $$[$0]);
    2261 break;
    2262 case 8:
    2263  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_delete', $$[$0]);
    2264 break;
    2265 case 9:
    2266  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_return', undefined);
    2267 break;
    2268 case 10:
    2269  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_return', $$[$0-1]);
    2270 break;
    2271 case 11: case 14:
    2272  this.$ = AST.createNode(lc(_$[$0]), 'node_op', 'op_none');
    2273 break;
    2274 case 12:
    2275  this.$ = $$[$0-1]; this.$.needsBrackets = true;
    2276 break;
    2277 case 13:
    2278  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_none', $$[$0-1], $$[$0]);
    2279 break;
    2280 case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 23: case 24: case 26: case 28: case 30: case 32: case 36: case 41: case 44: case 48: case 50: case 52: case 54: case 55: case 56: case 58: case 62: case 81: case 84: case 85: case 86:
    2281  this.$ = $$[$0];
    2282 break;
    2283 case 22: case 65: case 93:
    2284  this.$ = $$[$0-1];
    2285 break;
    2286 case 25:
    2287  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_assign', $$[$0-2], $$[$0]); this.$.isMath = false;
    2288 break;
    2289 case 27:
    2290  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_conditional', $$[$0-4], $$[$0-2], $$[$0]); this.$.isMath = false;
    2291 break;
    2292 case 29:
    2293  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_or', $$[$0-2], $$[$0]); this.$.isMath = false;
    2294 break;
    2295 case 31:
    2296  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_and', $$[$0-2], $$[$0]); this.$.isMath = false;
    2297 break;
    2298 case 33:
    2299  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_equ', $$[$0-2], $$[$0]); this.$.isMath = false;
    2300 break;
    2301 case 34:
    2302  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_neq', $$[$0-2], $$[$0]); this.$.isMath = false;
    2303 break;
    2304 case 35:
    2305  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_approx', $$[$0-2], $$[$0]); this.$.isMath = false;
    2306 break;
    2307 case 37:
    2308  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_lot', $$[$0-2], $$[$0]); this.$.isMath = false;
    2309 break;
    2310 case 38:
    2311  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_grt', $$[$0-2], $$[$0]); this.$.isMath = false;
    2312 break;
    2313 case 39:
    2314  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_loe', $$[$0-2], $$[$0]); this.$.isMath = false;
    2315 break;
    2316 case 40:
    2317  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_gre', $$[$0-2], $$[$0]); this.$.isMath = false;
    2318 break;
    2319 case 42:
    2320  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_add', $$[$0-2], $$[$0]); this.$.isMath = true;
    2321 break;
    2322 case 43:
    2323  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_sub', $$[$0-2], $$[$0]); this.$.isMath = true;
    2324 break;
    2325 case 45:
    2326  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mul', $$[$0-2], $$[$0]); this.$.isMath = true;
    2327 break;
    2328 case 46:
    2329  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_div', $$[$0-2], $$[$0]); this.$.isMath = true;
    2330 break;
    2331 case 47:
    2332  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mod', $$[$0-2], $$[$0]); this.$.isMath = true;
    2333 break;
    2334 case 49:
    2335  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_exp', $$[$0-2], $$[$0]); this.$.isMath = true;
    2336 break;
    2337 case 51:
    2338  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_not', $$[$0]); this.$.isMath = false;
    2339 break;
    2340 case 53:
    2341  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_neg', $$[$0]); this.$.isMath = true;
    2342 break;
    2343 case 57: case 63: case 64: case 66: case 67: case 68: case 97:
    2344  this.$ = $$[$0]; this.$.isMath = false;
    2345 break;
    2346 case 59: case 91:
    2347  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_property', $$[$0-2], $$[$0]); this.$.isMath = true;
    2348 break;
    2349 case 60: case 90:
    2350  this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_extvalue', $$[$0-3], $$[$0-1]); this.$.isMath = true;
    2351 break;
    2352 case 61:
    2353  this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]);
    2354 break;
    2355 case 69:
    2356  this.$ = $$[$0]; this.$.isMath = true;
    2357 break;
    2358 case 70:
    2359  this.$ = AST.createNode(lc(_$[$0]), 'node_const', null);
    2360 break;
    2361 case 71:
    2362  this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', true);
    2363 break;
    2364 case 72:
    2365  this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', false);
    2366 break;
    2367 case 73:
    2368  this.$ = AST.createNode(lc(_$[$0]), 'node_str', $$[$0].substring(1, $$[$0].length - 1));
    2369 break;
    2370 case 74:
    2371  this.$ = AST.createNode(lc(_$[$0]), 'node_const', parseFloat($$[$0]));
    2372 break;
    2373 case 75:
    2374  this.$ = AST.createNode(lc(_$[$0]), 'node_const', NaN);
    2375 break;
    2376 case 76:
    2377  this.$ = AST.createNode(lc(_$[$0]), 'node_const', Infinity);
    2378 break;
    2379 case 77:
    2380  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_array', []);
    2381 break;
    2382 case 78:
    2383  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_array', $$[$0-1]);
    2384 break;
    2385 case 79:
    2386  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_emptyobject', {});
    2387 break;
    2388 case 80:
    2389  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst_val', $$[$0-1]);
    2390 break;
    2391 case 82:
    2392  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst', $$[$0-2], $$[$0]);
    2393 break;
    2394 case 83:
    2395  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_prop', $$[$0-2], $$[$0]);
    2396 break;
    2397 case 87: case 89:
    2398  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_execfun', $$[$0-1], $$[$0]); this.$.isMath = true;
    2399 break;
    2400 case 88:
    2401  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_execfun', $$[$0-2], $$[$0-1], $$[$0], true); this.$.isMath = false;
    2402 break;
    2403 case 92:
    2404  this.$ = [];
    2405 break;
    2406 case 94: case 98: case 103:
    2407  this.$ = [$$[$0]];
    2408 break;
    2409 case 95: case 99: case 104:
    2410  this.$ = $$[$0-2].concat($$[$0]);
    2411 break;
    2412 case 96:
    2413  this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); this.$.isMath = true;
    2414 break;
    2415 case 100:
    2416  this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_function', [], $$[$0]); this.$.isMath = false;
    2417 break;
    2418 case 101:
    2419  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_function', $$[$0-2], $$[$0]); this.$.isMath = false;
    2420 break;
    2421 case 102:
    2422  this.$ = AST.createNode(lc(_$[$0-5]), 'node_op', 'op_map', $$[$0-3], $$[$0]);
    2423 break;
    2424 }
    2425 },
    2426 table: [o([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{1:[2,1]},o($Vq,[2,13]),o($Vr,[2,15]),o($Vr,[2,16]),o($Vr,[2,17]),o($Vr,[2,18]),o($Vr,[2,19]),o($Vr,[2,20]),o($Vr,[2,21]),o([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:$V1,8:$V2,9:20,11:65,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,66]},{20:[1,67]},{8:$V2,9:69,16:[1,68],20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,70]},o($Vr,[2,11]),o($Vs,[2,23]),o($Vs,[2,24]),o([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{32:[1,71],57:$Vu}),o([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),o($Vv,[2,54],{88:77,8:$Vw,64:[1,75],65:[1,76]}),o($Vv,[2,55],{88:79,8:$Vw,64:[1,81],65:[1,80]}),o($Vx,[2,28],{39:$Vy}),o($Vs,[2,56]),o($Vs,[2,57]),o($Vs,[2,58]),o($Vz,[2,30],{41:$VA,42:$VB,43:$VC}),o($Vs,[2,61]),o($Vs,[2,62]),o($Vs,[2,63]),o($Vs,[2,64]),{8:$V2,9:86,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:[1,87]},{8:[1,88]},o($VD,[2,32],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,66]),o($Vs,[2,67]),o($Vs,[2,68]),o($Vs,[2,69]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,83:[1,93],84:94,85:95,87:96},{8:$V2,20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:101,82:$Vn,91:$Vo,93:$Vp},o($VJ,[2,36],{50:$VK,51:$VL}),o($Vs,[2,70]),o($Vs,[2,71]),o($Vs,[2,72]),o($Vs,[2,73]),o($Vs,[2,74]),o($Vs,[2,75]),o($Vs,[2,76]),o($VM,[2,41],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,44]),o($Vs,[2,50]),{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:108,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:110,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:111,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:113,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:114,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:115,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{14:[1,116]},o($Vr,[2,7]),o($Vr,[2,8]),o($Vr,[2,9]),{16:[1,117]},o($Vr,[2,22]),{8:$V2,20:$V8,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:119,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,36:121,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,122]},{8:$V2,9:123,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,87],{89:124,90:125,68:127,20:$VQ,82:$Vn}),{8:$V2,10:[1,128],20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:129,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,89]),{8:$V2,9:130,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,131]},{8:$V2,20:$V8,31:109,38:132,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:133,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:134,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:135,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{10:[1,136]},{10:[1,137],20:$VR,92:138},{20:$VR,92:140},{8:$V2,20:$V8,31:109,44:141,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:142,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:143,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:144,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,79]),{83:[1,145],86:[1,146]},o($VS,[2,81]),{35:[1,147]},{35:[2,84]},{35:[2,85]},{35:[2,86]},o($Vs,[2,77]),{66:[1,148],86:$VT},o($VU,[2,98]),{8:$V2,20:$V8,31:109,49:150,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,49:151,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:152,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:153,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:154,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,51]),o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{57:$Vu}),o($Vs,[2,52]),o($Vs,[2,53]),o([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,155]},{10:[1,156]},{16:[1,157]},{8:[1,158]},o($Vr,[2,10]),o($Vs,[2,25]),o($Vs,[2,49]),{35:[1,159]},o($Vx,[2,29],{39:$Vy}),o($Vs,[2,59]),{66:[1,160]},o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,161]}),o($Vs,[2,94]),o($Vs,[2,96]),o($Vs,[2,97]),o($VV,[2,92]),{10:[1,162],86:$VT},{66:[1,163]},o($Vs,[2,91]),o($Vz,[2,31],{41:$VA,42:$VB,43:$VC}),o($VD,[2,33],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,34],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,35],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,65]),{25:164,26:$Vb},{10:[1,165],86:$VW},o($VX,[2,103]),{10:[1,167],86:$VW},o($VJ,[2,37],{50:$VK,51:$VL}),o($VJ,[2,38],{50:$VK,51:$VL}),o($VJ,[2,39],{50:$VK,51:$VL}),o($VJ,[2,40],{50:$VK,51:$VL}),o($Vs,[2,80]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,85:168,87:96},{8:$V2,20:$V8,29:169,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,78]),{8:$V2,20:$V8,29:170,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($VM,[2,42],{53:$VN,54:$VO,55:$VP}),o($VM,[2,43],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,45]),o($Vs,[2,46]),o($Vs,[2,47]),{6:6,7:$V1,8:$V2,9:20,11:171,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:172,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:173,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:174,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:175,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,60]),{20:$VQ,68:127,82:$Vn,90:176},o($VV,[2,93]),o($Vs,[2,90]),o($Vs,[2,100]),{25:177,26:$Vb},{20:[1,178]},{94:[1,179]},o($VS,[2,82]),o($VS,[2,83]),o($VU,[2,99]),o($Vq,[2,2],{12:[1,180]}),o($Vr,[2,4]),{16:[1,181]},{10:[1,182]},o($Vs,[2,27]),o($Vs,[2,95]),o($Vs,[2,101]),o($VX,[2,104]),{8:$V2,9:183,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:184,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:185,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,186]},o($Vs,[2,102]),o($Vr,[2,3]),{10:[1,187]},o($Vr,[2,6]),{6:6,7:$V1,8:$V2,9:20,11:188,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vr,[2,5])],
    2427 defaultActions: {3:[2,1],97:[2,84],98:[2,85],99:[2,86]},
    2428 parseError: function parseError(str, hash) {
    2429     if (hash.recoverable) {
    2430         this.trace(str);
    2431     } else {
    2432         function _parseError (msg, hash) {
    2433             this.message = msg;
    2434             this.hash = hash;
    2435         }
    2436         _parseError.prototype = Error;
    2437
    2438         throw new _parseError(str, hash);
    2439     }
    2440 },
    2441 parse: function parse(input) {
    2442     var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
    2443     var args = lstack.slice.call(arguments, 1);
    2444     var lexer = Object.create(this.lexer);
    2445     var sharedState = { yy: {} };
    2446     for (var k in this.yy) {
    2447         if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
    2448             sharedState.yy[k] = this.yy[k];
    2449         }
    2450     }
    2451     lexer.setInput(input, sharedState.yy);
    2452     sharedState.yy.lexer = lexer;
    2453     sharedState.yy.parser = this;
    2454     if (typeof lexer.yylloc == 'undefined') {
    2455         lexer.yylloc = {};
    2456     }
    2457     var yyloc = lexer.yylloc;
    2458     lstack.push(yyloc);
    2459     var ranges = lexer.options && lexer.options.ranges;
    2460     if (typeof sharedState.yy.parseError === 'function') {
    2461         this.parseError = sharedState.yy.parseError;
    2462     } else {
    2463         this.parseError = Object.getPrototypeOf(this).parseError;
    2464     }
    2465     function popStack(n) {
    2466         stack.length = stack.length - 2 * n;
    2467         vstack.length = vstack.length - n;
    2468         lstack.length = lstack.length - n;
    2469     }
    2470     _token_stack:
    2471         var lex = function () {
    2472             var token;
    2473             token = lexer.lex() || EOF;
    2474             if (typeof token !== 'number') {
    2475                 token = self.symbols_[token] || token;
    2476             }
    2477             return token;
    2478         };
    2479     var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
    2480     while (true) {
    2481         state = stack[stack.length - 1];
    2482         if (this.defaultActions[state]) {
    2483             action = this.defaultActions[state];
    2484         } else {
    2485             if (symbol === null || typeof symbol == 'undefined') {
    2486                 symbol = lex();
    2487             }
    2488             action = table[state] && table[state][symbol];
    2489         }
    2490                     if (typeof action === 'undefined' || !action.length || !action[0]) {
    2491                 var errStr = '';
    2492                 expected = [];
    2493                 for (p in table[state]) {
    2494                     if (this.terminals_[p] && p > TERROR) {
    2495                         expected.push('\'' + this.terminals_[p] + '\'');
    2496                     }
    2497                 }
    2498                 if (lexer.showPosition) {
    2499                     errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
    2500                 } else {
    2501                     errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
    2502                 }
    2503                 this.parseError(errStr, {
    2504                     text: lexer.match,
    2505                     token: this.terminals_[symbol] || symbol,
    2506                     line: lexer.yylineno,
    2507                     loc: yyloc,
    2508                     expected: expected
    2509                 });
    2510             }
    2511         if (action[0] instanceof Array && action.length > 1) {
    2512             throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
    2513         }
    2514         switch (action[0]) {
    2515         case 1:
    2516             stack.push(symbol);
    2517             vstack.push(lexer.yytext);
    2518             lstack.push(lexer.yylloc);
    2519             stack.push(action[1]);
    2520             symbol = null;
    2521             if (!preErrorSymbol) {
    2522                 yyleng = lexer.yyleng;
    2523                 yytext = lexer.yytext;
    2524                 yylineno = lexer.yylineno;
    2525                 yyloc = lexer.yylloc;
    2526                 if (recovering > 0) {
    2527                     recovering--;
    2528                 }
    2529             } else {
    2530                 symbol = preErrorSymbol;
    2531                 preErrorSymbol = null;
    2532             }
    2533             break;
    2534         case 2:
    2535             len = this.productions_[action[1]][1];
    2536             yyval.$ = vstack[vstack.length - len];
    2537             yyval._$ = {
    2538                 first_line: lstack[lstack.length - (len || 1)].first_line,
    2539                 last_line: lstack[lstack.length - 1].last_line,
    2540                 first_column: lstack[lstack.length - (len || 1)].first_column,
    2541                 last_column: lstack[lstack.length - 1].last_column
    2542             };
    2543             if (ranges) {
    2544                 yyval._$.range = [
    2545                     lstack[lstack.length - (len || 1)].range[0],
    2546                     lstack[lstack.length - 1].range[1]
    2547                 ];
    2548             }
    2549             r = this.performAction.apply(yyval, [
    2550                 yytext,
    2551                 yyleng,
    2552                 yylineno,
    2553                 sharedState.yy,
    2554                 action[1],
    2555                 vstack,
    2556                 lstack
    2557             ].concat(args));
    2558             if (typeof r !== 'undefined') {
    2559                 return r;
    2560             }
    2561             if (len) {
    2562                 stack = stack.slice(0, -1 * len * 2);
    2563                 vstack = vstack.slice(0, -1 * len);
    2564                 lstack = lstack.slice(0, -1 * len);
    2565             }
    2566             stack.push(this.productions_[action[1]][0]);
    2567             vstack.push(yyval.$);
    2568             lstack.push(yyval._$);
    2569             newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
    2570             stack.push(newState);
    2571             break;
    2572         case 3:
    2573             return true;
    2574         }
    2575     }
    2576     return true;
    2577 }};
    2578
    2579
    2580     var AST = {
    2581         node: function (type, value, children) {
    2582             return {
    2583                 type: type,
    2584                 value: value,
    2585                 children: children
    2586             };
    2587         },
    2588
    2589         createNode: function (pos, type, value, children) {
    2590             var i,
    2591                 n = this.node(type, value, []);
    2592
    2593             for (i = 3; i < arguments.length; i++) {
    2594                 n.children.push(arguments[i]);
    2595             }
    2596
    2597             n.line = pos[0];
    2598             n.col = pos[1];
    2599             n.eline = pos[2];
    2600             n.ecol = pos[3];
    2601
    2602             return n;
    2603         }
    2604     };
    2605
    2606     var lc = function (lc1) {
    2607         return [lc1.first_line, lc1.first_column, lc1.last_line, lc1.last_column];
    2608     };
    2609
    2610 /* generated by jison-lex 0.3.4 */
    2611 var lexer = (function(){
    2612 var lexer = ({
    2613
    2614 EOF:1,
    2615
    2616 parseError:function parseError(str, hash) {
    2617         if (this.yy.parser) {
    2618             this.yy.parser.parseError(str, hash);
    2619         } else {
    2620             throw new Error(str);
    2621         }
    2622     },
    2623
    2624 // resets the lexer, sets new input
    2625 setInput:function (input, yy) {
    2626         this.yy = yy || this.yy || {};
    2627         this._input = input;
    2628         this._more = this._backtrack = this.done = false;
    2629         this.yylineno = this.yyleng = 0;
    2630         this.yytext = this.matched = this.match = '';
    2631         this.conditionStack = ['INITIAL'];
    2632         this.yylloc = {
    2633             first_line: 1,
    2634             first_column: 0,
    2635             last_line: 1,
    2636             last_column: 0
    2637         };
    2638         if (this.options.ranges) {
    2639             this.yylloc.range = [0,0];
    2640         }
    2641         this.offset = 0;
    2642         return this;
    2643     },
    2644
    2645 // consumes and returns one char from the input
    2646 input:function () {
    2647         var ch = this._input[0];
    2648         this.yytext += ch;
    2649         this.yyleng++;
    2650         this.offset++;
    2651         this.match += ch;
    2652         this.matched += ch;
    2653         var lines = ch.match(/(?:\r\n?|\n).*/g);
    2654         if (lines) {
    2655             this.yylineno++;
    2656             this.yylloc.last_line++;
    2657         } else {
    2658             this.yylloc.last_column++;
    2659         }
    2660         if (this.options.ranges) {
    2661             this.yylloc.range[1]++;
    2662         }
    2663
    2664         this._input = this._input.slice(1);
    2665         return ch;
    2666     },
    2667
    2668 // unshifts one char (or a string) into the input
    2669 unput:function (ch) {
    2670         var len = ch.length;
    2671         var lines = ch.split(/(?:\r\n?|\n)/g);
    2672
    2673         this._input = ch + this._input;
    2674         this.yytext = this.yytext.substr(0, this.yytext.length - len);
    2675         //this.yyleng -= len;
    2676         this.offset -= len;
    2677         var oldLines = this.match.split(/(?:\r\n?|\n)/g);
    2678         this.match = this.match.substr(0, this.match.length - 1);
    2679         this.matched = this.matched.substr(0, this.matched.length - 1);
    2680
    2681         if (lines.length - 1) {
    2682             this.yylineno -= lines.length - 1;
    2683         }
    2684         var r = this.yylloc.range;
    2685
    2686         this.yylloc = {
    2687             first_line: this.yylloc.first_line,
    2688             last_line: this.yylineno + 1,
    2689             first_column: this.yylloc.first_column,
    2690             last_column: lines ?
    2691                 (lines.length === oldLines.length ? this.yylloc.first_column : 0)
    2692                  + oldLines[oldLines.length - lines.length].length - lines[0].length :
    2693               this.yylloc.first_column - len
    2694         };
    2695
    2696         if (this.options.ranges) {
    2697             this.yylloc.range = [r[0], r[0] + this.yyleng - len];
    2698         }
    2699         this.yyleng = this.yytext.length;
    2700         return this;
    2701     },
    2702
    2703 // When called from action, caches matched text and appends it on next action
    2704 more:function () {
    2705         this._more = true;
    2706         return this;
    2707     },
    2708
    2709 // 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.
    2710 reject:function () {
    2711         if (this.options.backtrack_lexer) {
    2712             this._backtrack = true;
    2713         } else {
    2714             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(), {
    2715                 text: "",
    2716                 token: null,
    2717                 line: this.yylineno
    2718             });
    2719
    2720         }
    2721         return this;
    2722     },
    2723
    2724 // retain first n characters of the match
    2725 less:function (n) {
    2726         this.unput(this.match.slice(n));
    2727     },
    2728
    2729 // displays already matched input, i.e. for error messages
    2730 pastInput:function () {
    2731         var past = this.matched.substr(0, this.matched.length - this.match.length);
    2732         return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
    2733     },
    2734
    2735 // displays upcoming input, i.e. for error messages
    2736 upcomingInput:function () {
    2737         var next = this.match;
    2738         if (next.length < 20) {
    2739             next += this._input.substr(0, 20-next.length);
    2740         }
    2741         return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
    2742     },
    2743
    2744 // displays the character position where the lexing error occurred, i.e. for error messages
    2745 showPosition:function () {
    2746         var pre = this.pastInput();
    2747         var c = new Array(pre.length + 1).join("-");
    2748         return pre + this.upcomingInput() + "\n" + c + "^";
    2749     },
    2750
    2751 // test the lexed token: return FALSE when not a match, otherwise return token
    2752 test_match:function (match, indexed_rule) {
    2753         var token,
    2754             lines,
    2755             backup;
    2756
    2757         if (this.options.backtrack_lexer) {
    2758             // save context
    2759             backup = {
    2760                 yylineno: this.yylineno,
    2761                 yylloc: {
    2762                     first_line: this.yylloc.first_line,
    2763                     last_line: this.last_line,
    2764                     first_column: this.yylloc.first_column,
    2765                     last_column: this.yylloc.last_column
    2766                 },
    2767                 yytext: this.yytext,
    2768                 match: this.match,
    2769                 matches: this.matches,
    2770                 matched: this.matched,
    2771                 yyleng: this.yyleng,
    2772                 offset: this.offset,
    2773                 _more: this._more,
    2774                 _input: this._input,
    2775                 yy: this.yy,
    2776                 conditionStack: this.conditionStack.slice(0),
    2777                 done: this.done
    2778             };
    2779             if (this.options.ranges) {
    2780                 backup.yylloc.range = this.yylloc.range.slice(0);
    2781             }
    2782         }
    2783
    2784         lines = match[0].match(/(?:\r\n?|\n).*/g);
    2785         if (lines) {
    2786             this.yylineno += lines.length;
    2787         }
    2788         this.yylloc = {
    2789             first_line: this.yylloc.last_line,
    2790             last_line: this.yylineno + 1,
    2791             first_column: this.yylloc.last_column,
    2792             last_column: lines ?
    2793                          lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
    2794                          this.yylloc.last_column + match[0].length
    2795         };
    2796         this.yytext += match[0];
    2797         this.match += match[0];
    2798         this.matches = match;
    2799         this.yyleng = this.yytext.length;
    2800         if (this.options.ranges) {
    2801             this.yylloc.range = [this.offset, this.offset += this.yyleng];
    2802         }
    2803         this._more = false;
    2804         this._backtrack = false;
    2805         this._input = this._input.slice(match[0].length);
    2806         this.matched += match[0];
    2807         token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
    2808         if (this.done && this._input) {
    2809             this.done = false;
    2810         }
    2811         if (token) {
    2812             return token;
    2813         } else if (this._backtrack) {
    2814             // recover context
    2815             for (var k in backup) {
    2816                 this[k] = backup[k];
    2817             }
    2818             return false; // rule action called reject() implying the next rule should be tested instead.
    2819         }
    2820         return false;
    2821     },
    2822
    2823 // return next match in input
    2824 next:function () {
    2825         if (this.done) {
    2826             return this.EOF;
    2827         }
    2828         if (!this._input) {
    2829             this.done = true;
    2830         }
    2831
    2832         var token,
    2833             match,
    2834             tempMatch,
    2835             index;
    2836         if (!this._more) {
    2837             this.yytext = '';
    2838             this.match = '';
    2839         }
    2840         var rules = this._currentRules();
    2841         for (var i = 0; i < rules.length; i++) {
    2842             tempMatch = this._input.match(this.rules[rules[i]]);
    2843             if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
    2844                 match = tempMatch;
    2845                 index = i;
    2846                 if (this.options.backtrack_lexer) {
    2847                     token = this.test_match(tempMatch, rules[i]);
    2848                     if (token !== false) {
    2849                         return token;
    2850                     } else if (this._backtrack) {
    2851                         match = false;
    2852                         continue; // rule action called reject() implying a rule MISmatch.
    2853                     } else {
    2854                         // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
    2855                         return false;
    2856                     }
    2857                 } else if (!this.options.flex) {
    2858                     break;
    2859                 }
    2860             }
    2861         }
    2862         if (match) {
    2863             token = this.test_match(match, rules[index]);
    2864             if (token !== false) {
    2865                 return token;
    2866             }
    2867             // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
    2868             return false;
    2869         }
    2870         if (this._input === "") {
    2871             return this.EOF;
    2872         } else {
    2873             return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
    2874                 text: "",
    2875                 token: null,
    2876                 line: this.yylineno
    2877             });
    2878         }
    2879     },
    2880
    2881 // return next match that has a token
    2882 lex:function lex() {
    2883         var r = this.next();
    2884         if (r) {
    2885             return r;
    2886         } else {
    2887             return this.lex();
    2888         }
    2889     },
    2890
    2891 // activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
    2892 begin:function begin(condition) {
    2893         this.conditionStack.push(condition);
    2894     },
    2895
    2896 // pop the previously active lexer condition state off the condition stack
    2897 popState:function popState() {
    2898         var n = this.conditionStack.length - 1;
    2899         if (n > 0) {
    2900             return this.conditionStack.pop();
    2901         } else {
    2902             return this.conditionStack[0];
    2903         }
    2904     },
    2905
    2906 // produce the lexer rule set which is active for the currently active lexer condition state
    2907 _currentRules:function _currentRules() {
    2908         if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
    2909             return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
    2910         } else {
    2911             return this.conditions["INITIAL"].rules;
    2912         }
    2913     },
    2914
    2915 // return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
    2916 topState:function topState(n) {
    2917         n = this.conditionStack.length - 1 - Math.abs(n || 0);
    2918         if (n >= 0) {
    2919             return this.conditionStack[n];
    2920         } else {
    2921             return "INITIAL";
    2922         }
    2923     },
    2924
    2925 // alias for begin(condition)
    2926 pushState:function pushState(condition) {
    2927         this.begin(condition);
    2928     },
    2929
    2930 // return the number of states currently on the stack
    2931 stateStackSize:function stateStackSize() {
    2932         return this.conditionStack.length;
    2933     },
    2934 options: {},
    2935 performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
    2936 var YYSTATE=YY_START;
    2937 switch($avoiding_name_collisions) {
    2938 case 0:/* ignore */
    2939 break;
    2940 case 1:return 78
    2941 break;
    2942 case 2:return 78
    2943 break;
    2944 case 3: return 77;
    2945 break;
    2946 case 4: return 77;
    2947 break;
    2948 case 5:/* ignore comment */
    2949 break;
    2950 case 6:/* ignore multiline comment */
    2951 break;
    2952 case 7:return 7
    2953 break;
    2954 case 8:return 12
    2955 break;
    2956 case 9:return 14
    2957 break;
    2958 case 10:return 17
    2959 break;
    2960 case 11:return 15
    2961 break;
    2962 case 12:return 91
    2963 break;
    2964 case 13:return 93
    2965 break;
    2966 case 14:return 19
    2967 break;
    2968 case 15:return 23
    2969 break;
    2970 case 16:return 21
    2971 break;
    2972 case 17:return 75
    2973 break;
    2974 case 18:return 76
    2975 break;
    2976 case 19:return 74
    2977 break;
    2978 case 20:return 80
    2979 break;
    2980 case 21:return 94
    2981 break;
    2982 case 22:return 82
    2983 break;
    2984 case 23:return 83
    2985 break;
    2986 case 24:return 26
    2987 break;
    2988 case 25:return 27
    2989 break;
    2990 case 26:return 16
    2991 break;
    2992 case 27:return '#'
    2993 break;
    2994 case 28:return 34
    2995 break;
    2996 case 29:return 35
    2997 break;
    2998 case 30:return 79
    2999 break;
    3000 case 31:return 64
    3001 break;
    3002 case 32:return 65
    3003 break;
    3004 case 33:return 66
    3005 break;
    3006 case 34:return 8
    3007 break;
    3008 case 35:return 10
    3009 break;
    3010 case 36:return 58
    3011 break;
    3012 case 37:return 57
    3013 break;
    3014 case 38:return 53
    3015 break;
    3016 case 39:return 54
    3017 break;
    3018 case 40:return 55
    3019 break;
    3020 case 41:return 50
    3021 break;
    3022 case 42:return 51
    3023 break;
    3024 case 43:return 47
    3025 break;
    3026 case 44:return 45
    3027 break;
    3028 case 45:return 48
    3029 break;
    3030 case 46:return 46
    3031 break;
    3032 case 47:return 41
    3033 break;
    3034 case 48:return 43
    3035 break;
    3036 case 49:return 42
    3037 break;
    3038 case 50:return 39
    3039 break;
    3040 case 51:return 37
    3041 break;
    3042 case 52:return 32
    3043 break;
    3044 case 53:return 86
    3045 break;
    3046 case 54:return 5
    3047 break;
    3048 case 55:return 20
    3049 break;
    3050 case 56:return 'INVALID'
    3051 break;
    3052 }
    3053 },
    3054 rules: [/^(?:\s+)/,/^(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+\b)/,/^(?:[0-9]+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:\/\/.*)/,/^(?:\/\*(.|\n|\r)*?\*\/)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:while\b)/,/^(?:do\b)/,/^(?:for\b)/,/^(?:function\b)/,/^(?:map\b)/,/^(?:use\b)/,/^(?:return\b)/,/^(?:delete\b)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:Infinity\b)/,/^(?:->)/,/^(?:<<)/,/^(?:>>)/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:#)/,/^(?:\?)/,/^(?::)/,/^(?:NaN\b)/,/^(?:\.)/,/^(?:\[)/,/^(?:\])/,/^(?:\()/,/^(?:\))/,/^(?:!)/,/^(?:\^)/,/^(?:\*)/,/^(?:\/)/,/^(?:%)/,/^(?:\+)/,/^(?:-)/,/^(?:<=)/,/^(?:<)/,/^(?:>=)/,/^(?:>)/,/^(?:==)/,/^(?:~=)/,/^(?:!=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:=)/,/^(?:,)/,/^(?:$)/,/^(?:[A-Za-z_\$][A-Za-z0-9_]*)/,/^(?:.)/],
    3055 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,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56],"inclusive":true}}
    3056 });
    3057 return lexer;
    3058 })();
    3059 parser.lexer = lexer;
    3060 function Parser () {
    3061   this.yy = {};
    3062 }
    3063 Parser.prototype = parser;parser.Parser = Parser;
    3064 return new Parser;
    3065 })();
    3066
    3067
    3068 if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
    3069 exports.parser = parser;
    3070 exports.Parser = parser.Parser;
    3071 exports.parse = function () { return parser.parse.apply(parser, arguments); };
    3072 exports.main = function commonjsMain(args) {
    3073     if (!args[1]) {
    3074         console.log('Usage: '+args[0]+' FILE');
    3075         process.exit(1);
    3076     }
    3077     var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
    3078     return exports.parser.parse(source);
    3079 };
    3080 if (typeof module !== 'undefined' && require.main === module) {
    3081   exports.main(process.argv.slice(1));
    3082 }
    3083 }
    3084
    3085     // Work around an issue with browsers that don't support Object.getPrototypeOf()
    3086     parser.yy.parseError = parser.parseError;
    3087
    3088     return JXG.JessieCode;
    3089 });
    3090