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