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