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