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