/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.

*/

/**
 * JSXGraph namespace. Holds all classes, objects, functions and variables belonging to JSXGraph
 * to reduce the risc of interfering with other JavaScript code.
 * @namespace
 */
var JXG = {};

(function () {
    'use strict';

    var i, s;
    //JXG.useMinify = true;
    JXG.countDrawings = 0;
    JXG.countTime = 0;
    JXG.require = function (libraryName) {};
    JXG.rendererFiles = {
        svg: 'SVGRenderer',
        vml: 'VMLRenderer',
        canvas: 'CanvasRenderer'
    };
    JXG.baseFiles = null;
    // this maybe required by additional software/extensions and/or future renderers
    JXG.requirePath = '';

    if (typeof document === 'object' && document.getElementsByTagName) {
        for (i = 0; i < document.getElementsByTagName("script").length; i++) {
            s = document.getElementsByTagName("script")[i];

            if (s.src && s.src.match(/loadjsxgraphInOneFile\.js(\?.*)?$/)) {
                JXG.requirePath = s.src.replace(/loadjsxgraphInOneFile\.js(\?.*)?$/, '');
            }
        }
    }
    JXG.serverBase = JXG.requirePath + 'server/';

    if (typeof module === 'object') {
        module.exports = JXG;
    }

}());


/*
 Copyright 2008-2011
 Matthias Ehmann,
 Michael Gerhaeuser,
 Carsten Miller,
 Bianca Valentin,
 Alfred Wassermann,
 Peter Wilfahrt

 This file is part of JSXGraph.

 JSXGraph is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 JSXGraph is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
 */

/*global JXG: true */

/**
 * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards.
 * It has methods to create, save, load and free boards. Additionally some helper functions are
 * defined in this file directly in the JXG namespace.
 * @version 0.83
 */


// We need the following two methods "extend" and "shortcut" to create the JXG object via JXG.extend.

/**
 * Copy all properties of the <tt>extension</tt> object to <tt>object</tt>.
 * @param {Object} object
 * @param {Object} extension
 * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties.
 * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes
 */
JXG.extend = function (object, extension, onlyOwn, toLower) {
    var e, e2;

    onlyOwn = onlyOwn || false;
    toLower = toLower || false;

    for (e in extension) {
        if (!onlyOwn || (onlyOwn && extension.hasOwnProperty(e))) {
            if (toLower) {
                e2 = e.toLowerCase();
            } else {
                e2 = e;
            }

            object[e2] = extension[e];
        }
    }
};

/**
 * Creates a shortcut to a method, e.g. {@link JXG.Board#create} is a shortcut to {@link JXG.Board#createElement}.
 * Sometimes the target is undefined by the time you want to define the shortcut so we need this little helper.
 * @param {Object} object The object the method we want to create a shortcut for belongs to.
 * @param {Function} fun The method we want to create a shortcut for.
 * @returns {Function} A function that calls the given method.
 */
JXG.shortcut = function (object, fun) {
    return function () {
        return object[fun].apply(this, arguments);
    };
};


JXG.extend(JXG, /** @lends JXG */ {

    /**
     * Determines the property that stores the relevant information in the event object.
     * @type {String}
     * @default 'touches'
     */
    touchProperty: 'touches',


    /**
     * Represents the currently used JSXGraph version.
     * @type {String}
     */
    version: '0.97.1',

    /**
     * A document/window environment is available.
     * @type Boolean
     * @default false
     */
    isBrowser: typeof window === 'object' && typeof document === 'object',

    /**
     * Detect browser support for VML.
     * @returns {Boolean} True, if the browser supports VML.
     */
    supportsVML: function () {
        // From stackoverflow.com
        return this.isBrowser && !!document.namespaces;
    },

    /**
     * Detect browser support for SVG.
     * @returns {Boolean} True, if the browser supports SVG.
     */
    supportsSVG: function () {
        return this.isBrowser && document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1");
    },

    /**
     * Detect browser support for Canvas.
     * @returns {Boolean} True, if the browser supports HTML canvas.
     */
    supportsCanvas: function () {
        return this.isBrowser && !!document.createElement('canvas').getContext;
    },

    isNode: function () {
        // this is not a 100% sure but should be valid in most cases
        return !this.isBrowser && typeof module === 'object' && module.exports;
    },

    /**
     * Determine if the current browser supports touch events
     * @returns {Boolean} True, if the browser supports touch events.
     */
    isTouchDevice: function () {
        return this.isBrowser && document.documentElement.hasOwnProperty('ontouchstart');
    },

    /**
     * Detects if the user is using an Android powered device.
     * @returns {Boolean}
     */
    isAndroid: function () {
        return JXG.exists(navigator) && navigator.userAgent.toLowerCase().search("android") > -1;
    },

    /**
     * Detects if the user is using the default Webkit browser on an Android powered device.
     * @returns {Boolean}
     */
    isWebkitAndroid: function () {
        return this.isAndroid() && navigator.userAgent.search(" AppleWebKit/") > -1;
    },

    /**
     * Detects if the user is using a Apple iPad / iPhone.
     * @returns {Boolean}
     */
    isApple: function () {
        return JXG.exists(navigator) && (navigator.userAgent.search(/iPad/) != -1 || navigator.userAgent.search(/iPhone/) != -1);
    },

    /**
     * Detects if the user is using Safari on an Apple device.
     * @returns {Boolean}
     */
    isWebkitApple: function () {
        return this.isApple() && (navigator.userAgent.search(/Mobile *.*Safari/) > -1);
    },

    /**
     * Returns true if the run inside a Windows 8 "Metro" App.
     * @return {Boolean}
     */
    isMetroApp: function () {
        return typeof window === 'object' && window.clientInformation && window.clientInformation.appName && window.clientInformation.appName.indexOf('MSAppHost') > -1;
    },

    /**
     * Resets visPropOld of <tt>el</tt>
     * @param {JXG.GeometryElement} el
     */
    clearVisPropOld: function (el) {
        el.visPropOld = {
            strokecolor: '',
            strokeopacity: '',
            strokewidth: '',
            fillcolor: '',
            fillopacity: '',
            shadow: false,
            firstarrow: false,
            lastarrow: false,
            cssclass: '',
            fontsize: -1
        };
    },

    /**
     * Internet Explorer version. Works only for IE > 4.
     * @type Number
     */
    ieVersion: (function() {
        var undef;

        if (typeof document !== 'object') {
            return undef;
        }

        var v = 3,
            div = document.createElement('div'),
            all = div.getElementsByTagName('i');

        while (
            div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i><' + '/i><![endif]-->',
                all[0]
            );

        return v > 4 ? v : undef;

    }()),

    /**
     * s may be a string containing the name or id of an element or even a reference
     * to the element itself. This function returns a reference to the element. Search order: id, name.
     * @param {JXG.Board} board Reference to the board the element belongs to.
     * @param {String} s String or reference to a JSXGraph element.
     * @returns {Object} Reference to the object given in parameter object
     */
    getReference: function (board, s) {
        if (typeof(s) == 'string') {
            if (JXG.exists(board.objects[s])) { // Search by ID
                s = board.objects[s];
            } else if (JXG.exists(board.elementsByName[s])) { // Search by name
                s = board.elementsByName[s];
            } else if (JXG.exists(board.groups[s])) { // Search by group ID 
                s = board.groups[s];
            }
        }

        return s;
    },

    /**
     * This is just a shortcut to {@link JXG.getReference}.
     */
    getRef: JXG.shortcut(JXG, 'getReference'),

    /**
     * Checks if the given string is an id within the given board.
     * @param {JXG.Board} board
     * @param {String} s
     * @returns {Boolean}
     */
    isId: function (board, s) {
        return typeof(s) == 'string' && !!board.objects[s];
    },

    /**
     * Checks if the given string is a name within the given board.
     * @param {JXG.Board} board
     * @param {String} s
     * @returns {Boolean}
     */
    isName: function (board, s) {
        return typeof(s) == 'string' && !!board.elementsByName[s];
    },

    /**
     * Checks if the given string is a group id within the given board.
     * @param {JXG.Board} board
     * @param {String} s
     * @returns {Boolean}
     */
    isGroup: function (board, s) {
        return typeof(s) == 'string' && !!board.groups[s];
    },

    /**
     * Checks if the value of a given variable is of type string.
     * @param v A variable of any type.
     * @returns {Boolean} True, if v is of type string.
     */
    isString: function (v) {
        return typeof v === "string";
    },

    /**
     * Checks if the value of a given variable is of type number.
     * @param v A variable of any type.
     * @returns {Boolean} True, if v is of type number.
     */
    isNumber: function (v) {
        return typeof v === "number";
    },

    /**
     * Checks if a given variable references a function.
     * @param v A variable of any type.
     * @returns {Boolean} True, if v is a function.
     */
    isFunction: function (v) {
        return typeof v === "function";
    },

    /**
     * Checks if a given variable references an array.
     * @param v A variable of any type.
     * @returns {Boolean} True, if v is of type array.
     */
    isArray: function (v) {
        var r;

        // use the ES5 isArray() method and if that doesn't exist use a fallback.
        if (Array.isArray) {
            r = Array.isArray(v);
        } else {
            r = (v !== null && typeof v === "object" && 'splice' in v && 'join' in v);
        }

        return r;
    },

    /**
     * Checks if a given variable is a reference of a JSXGraph Point element.
     * @param v A variable of any type.
     * @returns {Boolean} True, if v is of type JXG.Point.
     */
    isPoint: function (v) {
        if (typeof v == 'object') {
            return (v.elementClass == JXG.OBJECT_CLASS_POINT);
        }

        return false;
    },

    /**
     * Checks if a given variable is neither undefined nor null. You should not use this together with global
     * variables!
     * @param v A variable of any type.
     * @returns {Boolean} True, if v is neither undefined nor null.
     */
    exists: (function (undefined) {
        return function (v) {
            return !(v === undefined || v === null);
        }
    })(),

    /**
     * Handle default parameters.
     * @param {} v Given value
     * @param {} d Default value
     * @returns {} <tt>d</tt>, if <tt>v</tt> is undefined or null.
     */
    def: function (v, d) {
        if (JXG.exists(v)) {
            return v;
        } else {
            return d;
        }
    },

    /**
     * Converts a string containing either <strong>true</strong> or <strong>false</strong> into a boolean value.
     * @param {String} s String containing either <strong>true</strong> or <strong>false</strong>.
     * @returns {Boolean} String typed boolean value converted to boolean.
     */
    str2Bool: function (s) {
        if (!JXG.exists(s)) {
            return true;
        }
        if (typeof s == 'boolean') {
            return s;
        }
        //return (s.toLowerCase()=='true');

        if (JXG.isString(s)) {
            return (s.toLowerCase()=='true');
        } else {
            return false;
        }

    },

    /**
     * Shortcut for {@link JXG.JSXGraph.initBoard}.
     */
    _board: function (box, attributes) {
        return JXG.JSXGraph.initBoard(box, attributes);
    },

    /**
     * Convert a String, a number or a function into a function. This method is used in Transformation.js
     * @param {JXG.Board} board Reference to a JSXGraph board. It is required to resolve dependencies given
     * by a GEONE<sub>X</sub>T string, thus it must be a valid reference only in case one of the param
     * values is of type string.
     * @param {Array} param An array containing strings, numbers, or functions.
     * @param {Number} n Length of <tt>param</tt>.
     * @returns {Function} A function taking one parameter k which specifies the index of the param element
     * to evaluate.
     */
    createEvalFunction: function (board, param, n) {
        // convert GEONExT syntax into function
        var f = [], i, str;

        for (i=0;i<n;i++) {
            if (typeof param[i] == 'string') {
                str = JXG.GeonextParser.geonext2JS(param[i],board);
                str = str.replace(/this\.board\./g,'board.');
                f[i] = new Function('','return ' + (str) + ';');
            }
        }

        return function (k) {
            var a = param[k];
            if (typeof a == 'string') {
                return f[k]();
            } else if (typeof a=='function') {
                return a();
            } else if (typeof a=='number') {
                return a;
            }
            return 0;
        };
    },

    /**
     * Convert a String, number or function into a function.
     * @param term A variable of type string, function or number.
     * @param {JXG.Board} board Reference to a JSXGraph board. It is required to resolve dependencies given
     * by a GEONE<sub>X</sub>T string, thus it must be a valid reference only in case one of the param
     * values is of type string.
     * @param {String} variableName Only required if evalGeonext is set to true. Describes the variable name
     * of the variable in a GEONE<sub>X</sub>T string given as term.
     * @param {Boolean} evalGeonext Set this true, if term should be treated as a GEONE<sub>X</sub>T string.
     * @returns {Function} A function evaluation the value given by term or null if term is not of type string,
     * function or number.
     */
    createFunction: function (term, board, variableName, evalGeonext) {
        var f = null;

        if ((!JXG.exists(evalGeonext) || evalGeonext) && JXG.isString(term)) {
            // Convert GEONExT syntax into  JavaScript syntax
            //newTerm = JXG.GeonextParser.geonext2JS(term, board);
            //return new Function(variableName,'return ' + newTerm + ';');
            f = board.jc.snippet(term, true, variableName, true);
        } else if (JXG.isFunction(term)) {
            f = term;
        } else if (JXG.isNumber(term)) {
            f = function () { return term; };
        } else if (JXG.isString(term)) {        // In case of string function like fontsize
            f = function () { return term; };
        }

        if (f !== null) {
            f.origin = term;
        }

        return f;
    },

    /**
     * Checks given parents array against several expectations.
     * @param {String} element The name of the element to be created
     * @param {Array} parents A parents array
     * @param {Array} expects Each possible parents array types combination is given as
     * an array of element type constants containing the types or names of elements that are
     * accepted and in what order they are accepted. Strings can be given for basic data types
     * are <em>number, string, array, function, object</em>. We accept non element JSXGraph
     * types like <em>coords</em>, too.
     * @returns {Array} A new parents array prepared for the use within a create* method
     */
    checkParents: function (element, parents, expects) {
        // some running variables
        var i, j, k, len,

        // collects the parent elements that already got verified
            new_parents = [],

        // in case of multiple parent array type combinations we may have to start over again
        // so hold the parents array in an temporary array in case we need the original one back
            tmp_parents = parents.slice(0),

        // test the given parent element against what we expect
            is = function (expect, parent) {
                // we basically got three cases:
                // expect is of type
                // number => test for parent.elementClass and parent.type
                //     lucky us elementClass and type constants don't overlap \o/
                // string => here we have two sub cases depending on the value of expect
                //   string, object, function, number => make a simple typeof
                //   array => check via isArray

                var type_expect = (typeof expect).toLowerCase();

                if (type_expect === 'number') {
                    return parent && ((parent.type && parent.type === expect) || (parent.elementClass && parent.elementClass === expect))
                } else {
                    switch(expect.toLowerCase()) {
                        case 'string':
                        case 'object':
                        case 'function':
                        case 'number':
                            return (typeof parent).toLowerCase() === expect.toLowerCase();
                            break;
                        case 'array':
                            return JXG.isArray(parent);
                            break;
                    }
                }


                return false;
            };


        for(i = 0; i < expects.length; i++) {
            // enter the next loop only if parents has enough elements
            for(j = 0; j < expects[i].length && parents.length >= expects[i].length; j++) {
                k = 0;
                while (k < tmp_parents.length && !is(expects[i][j], tmp_parents[k]))
                    k++;

                if (k<tmp_parents.length) {
                    new_parents.push(tmp_parents.splice(len-k-1, 1)[0]);
                }
            }

            // if there are still elements left in the parents array we need to
            // rebuild the original parents array and start with the next expect array
            if (tmp_parents.length) {
                tmp_parents = parents.slice(0);
                new_parents = [];
            } else // yay, we found something \o/
                return new_parents;
        }
    },

    /**
     * Reads the configuration parameter of an attribute of an element from a {@link JXG.Options} object
     * @param {JXG.Options} options Reference to an instance of JXG.Options. You usually want to use the
     * options property of your board.
     * @param {String} element The name of the element which options you wish to read, e.g. 'point' or
     * 'elements' for general attributes.
     * @param {String} key The name of the attribute to read, e.g. 'strokeColor' or 'withLabel'
     * @returns The value of the selected configuration parameter.
     * @see JXG.Options
     */
    readOption: function (options, element, key) {
        var val = options.elements[key];

        if (JXG.exists(options[element][key]))
            val = options[element][key];

        return val;
    },

    /**
     * Checks an attributes object and fills it with default values if there are properties missing.
     * @param {Object} attributes
     * @param {Object} defaults
     * @returns {Object} The given attributes object with missing properties added via the defaults object.
     * @deprecated replaced by JXG#copyAttributes
     */
    checkAttributes: function (attributes, defaults) {
        var key;

        // Make sure attributes is an object.
        if (!JXG.exists(attributes)) {
            attributes = {};
        }

        // Go through all keys of defaults and check for their existence
        // in attributes. If one doesn't exist, it is created with the
        // same value as in defaults.
        for (key in defaults) {
            if (!JXG.exists(attributes[key])) {
                attributes[key] = defaults[key];
            }
        }

        return attributes;
    },

    /**
     * Generates an attributes object that is filled with default values from the Options object
     * and overwritten by the user speciified attributes.
     * @param {Object} attributes user specified attributes
     * @param {Object} options defaults options
     * @param {String} % variable number of strings, e.g. 'slider', subtype 'point1'.
     * @returns {Object} The resulting attributes object
     */
    copyAttributes: function (attributes, options) {
        var a, i, len, o, isAvail,
            primitives = {
                'circle': 1,
                'curve': 1,
                'image': 1,
                'line': 1,
                'point': 1,
                'polygon': 1,
                'text': 1,
                'ticks': 1,
                'integral': 1
            };


        len = arguments.length;
        if (len < 3 || primitives[arguments[2]]) {
            a = this.deepCopy(options.elements, null, true);       // default options from Options.elements
        } else {
            a = {};
        }

        // Only the layer of the main element is set.
        if (len < 4 && this.exists(arguments[2]) && this.exists(options.layer[arguments[2]])) {
            a.layer = options.layer[arguments[2]];
        }

        o = options;                                                // default options from specific elements
        isAvail = true;
        for (i = 2; i < len; i++) {
            if (JXG.exists(o[arguments[i]])) {
                o = o[arguments[i]];
            } else {
                isAvail = false;
                break;
            }
        }
        if (isAvail) {
            a = this.deepCopy(a, o, true);
        }

        o = attributes;                                             // options from attributes
        isAvail = true;
        for (i=3;i<len;i++) {
            if (JXG.exists(o[arguments[i]])) {
                o = o[arguments[i]];
            } else {
                isAvail = false;
                break;
            }
        }
        if (isAvail) {
            this.extend(a, o, null, true);
        }

        /**
         * Special treatment of labels
         */
        o = options;
        isAvail = true;
        for (i = 2; i < len; i++) {
            if (JXG.exists(o[arguments[i]])) {
                o = o[arguments[i]];
            } else {
                isAvail = false;
                break;
            }
        }
        if (isAvail) {
            a.label =  JXG.deepCopy(o.label, a.label);
        }
        a.label = JXG.deepCopy(options.label, a.label);

        return a;
    },

    /**
     * Reads the width and height of an HTML element.
     * @param {String} elementId The HTML id of an HTML DOM node.
     * @returns {Object} An object with the two properties width and height.
     */
    getDimensions: function (elementId) {
        var element, display, els, originalVisibility, originalPosition,
            originalDisplay, originalWidth, originalHeight;

        if (typeof document == 'undefined' || elementId == null) {
            return {
                width: 500,
                height: 500
            };
        }

        // Borrowed from prototype.js
        element = document.getElementById(elementId);
        if (!JXG.exists(element)) {
            throw new Error("\nJSXGraph: HTML container element '" + (elementId) + "' not found.");
        }

        display = element.style.display;
        if (display != 'none' && display != null) {// Safari bug
            return {width: element.offsetWidth, height: element.offsetHeight};
        }

        // All *Width and *Height properties give 0 on elements with display set to none,
        // hence we show the element temporarily
        els = element.style;

        // save style
        originalVisibility = els.visibility;
        originalPosition = els.position;
        originalDisplay = els.display;

        // show element
        els.visibility = 'hidden';
        els.position = 'absolute';
        els.display = 'block';

        // read the dimension
        originalWidth = element.clientWidth;
        originalHeight = element.clientHeight;

        // restore original css values
        els.display = originalDisplay;
        els.position = originalPosition;
        els.visibility = originalVisibility;

        return {
            width: originalWidth,
            height: originalHeight
        };
    },

    /**
     * Adds an event listener to a DOM element.
     * @param {Object} obj Reference to a DOM node.
     * @param {String} type The event to catch, without leading 'on', e.g. 'mousemove' instead of 'onmousemove'.
     * @param {Function} fn The function to call when the event is triggered.
     * @param {Object} owner The scope in which the event trigger is called.
     */
    addEvent: function (obj, type, fn, owner) {
        var el = function () {
            return fn.apply(owner, arguments);
        };

        el.origin = fn;
        owner['x_internal'+type] = owner['x_internal'+type] || [];
        owner['x_internal'+type].push(el);

        if (JXG.exists(obj) && JXG.exists(obj.addEventListener)) { // Non-IE browser
            obj.addEventListener(type, el, false);
        } else {  // IE
            obj.attachEvent('on'+type, el);
        }
    },

    /**
     * Removes an event listener from a DOM element.
     * @param {Object} obj Reference to a DOM node.
     * @param {String} type The event to catch, without leading 'on', e.g. 'mousemove' instead of 'onmousemove'.
     * @param {Function} fn The function to call when the event is triggered.
     * @param {Object} owner The scope in which the event trigger is called.
     */
    removeEvent: function (obj, type, fn, owner) {
        var i;

        if (!JXG.exists(owner)) {
            JXG.debug('no such owner');
            return;
        }

        if (!JXG.exists(owner['x_internal' + type])) {
            JXG.debug('no such type: ' + type);
            return;
        }

        if (!JXG.isArray(owner['x_internal' + type])) {
            JXG.debug('owner[x_internal + ' + type + '] is not an array');
            return;
        }

        i = JXG.indexOf(owner['x_internal' + type], fn, 'origin');

        if (i === -1) {
            JXG.debug('no such event function in internal list: ' + fn);
            return;
        }

        try {
            if (JXG.exists(obj.addEventListener)) { // Non-IE browser
                obj.removeEventListener(type, owner['x_internal' + type][i], false);
            } else {  // IE
                obj.detachEvent('on' + type, owner['x_internal' + type][i]);
            }

        } catch(e) {
            JXG.debug('event not registered in browser: (' + type + ' -- ' + fn + ')');
        }

        owner['x_internal' + type].splice(i, 1);
    },

    /**
     * Removes all events of the given type from a given DOM node; Use with caution and do not use it on a container div
     * of a {@link JXG.Board} because this might corrupt the event handling system.
     * @param {Object} obj Reference to a DOM node.
     * @param {String} type The event to catch, without leading 'on', e.g. 'mousemove' instead of 'onmousemove'.
     * @param {Object} owner The scope in which the event trigger is called.
     */
    removeAllEvents: function(obj, type, owner) {
        var i, len;
        if (owner['x_internal' + type]) {
            len = owner['x_internal' + type].length;

            for (i = len - 1; i >= 0; i--) {
                JXG.removeEvent(obj, type, owner['x_internal' + type][i].origin, owner);
            }

            if (owner['x_internal' + type].length > 0) {
                JXG.debug('removeAllEvents: Not all events could be removed.');
            }
        }
    },

    /**
     * Generates a function which calls the function fn in the scope of owner.
     * @param {Function} fn Function to call.
     * @param {Object} owner Scope in which fn is executed.
     * @returns {Function} A function with the same signature as fn.
     */
    bind: function (fn, owner) {
        return function () {
            return fn.apply(owner,arguments);
        };
    },

    /**
     * Removes an element from the given array
     * @param {Array} ar
     * @param {%} el
     * @returns {Array}
     */
    removeElementFromArray: function(ar, el) {
        var i;

        for (i = 0; i < ar.length; i++) {
            if (ar[i] === el) {
                ar.splice(i, 1);
                return ar;
            }
        }

        return ar;
    },

    /**
     * Cross browser mouse / touch coordinates retrieval relative to the board's top left corner.
     * @param {Object} [e] The browsers event object. If omitted, <tt>window.event</tt> will be used.
     * @param {Number} [index] If <tt>e</tt> is a touch event, this provides the index of the touch coordinates, i.e. it determines which finger.
     * @returns {Array} Contains the position as x,y-coordinates in the first resp. second component.
     */
    getPosition: function (e, index) {
        var i, len, posx = 0, posy = 0,
            evtTouches;

        if (!e) {
            e = window.event;
        }
        evtTouches = e[JXG.touchProperty];

        if (JXG.exists(index)) {

            if (index == -1) {

                len = evtTouches.length;
                for (i=0; i<len; i++) {
                    if (evtTouches[i]) {
                        e = evtTouches[i];
                        break;
                    }
                }

            } else
                e = evtTouches[index];
        }

        if (e.pageX || e.pageY) {
            posx = e.pageX;
            posy = e.pageY;
        } else if (e.clientX || e.clientY)    {
            posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
            posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
        }
    
        return [posx,posy];
    },

    /**
     * Calculates recursively the offset of the DOM element in which the board is stored.
     * @param {Object} obj A DOM element
     * @returns {Array} An array with the elements left and top offset.
     */
    getOffset: function (obj) {
        var o = obj,
            o2 = obj,
            l = o.offsetLeft - o.scrollLeft,
            t = o.offsetTop - o.scrollTop,
            cPos;

        cPos = this.getCSSTransform([l,t],o);
        l = cPos[0];
        t = cPos[1];

        /*
         * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe,
         * if not to the body. In IE and if we are in an position:absolute environment 
         * offsetParent walks up the DOM hierarchy.
         * In order to walk up the DOM hierarchy also in Mozilla and Webkit
         * we need the parentNode steps.
         */
        while (o=o.offsetParent) {
            l+=o.offsetLeft;
            t+=o.offsetTop;
            if (o.offsetParent) {
                l+=o.clientLeft - o.scrollLeft;
                t+=o.clientTop - o.scrollTop;
            }
            
            cPos = this.getCSSTransform([l,t],o);
            l = cPos[0];
            t = cPos[1];
            
            o2 = o2.parentNode;
            while (o2!=o) {
                l += o2.clientLeft - o2.scrollLeft;
                t += o2.clientTop - o2.scrollTop;
                
                cPos = this.getCSSTransform([l,t],o2);
                l = cPos[0];
                t = cPos[1];

                o2 = o2.parentNode;
            }

        }
        return [l,t];
    },

    /**
     * Access CSS style sheets.
     * @param {Object} obj A DOM element
     * @param {String} stylename The CSS property to read.
     * @returns The value of the CSS property and <tt>undefined</tt> if it is not set.
     */
    getStyle: function (obj, stylename) {
        var r;

        if (window.getComputedStyle) {
            // Non-IE
            r = document.defaultView.getComputedStyle(obj, null).getPropertyValue(stylename);
        } else if (obj.currentStyle && JXG.ieVersion >= 9) {
            // IE
            r = obj.currentStyle[stylename];
        } else {
            if (obj.style) {
                // make stylename lower camelcase
                stylename = stylename.replace(/-([a-z]|[0-9])/ig, function (all, letter) {
                    return ( letter + "" ).toUpperCase();
                });
                r = obj.style[stylename]
            }
        }

        return r;
    },

    /**
     * Correct position of upper left corner in case of 
     * a CSS transformation.
     * @param {Array} cPos Previously determined position
     * @param {Object} obj A DOM element
     * @returns {Array} The corrected position.
     */
    getCSSTransform: function(cPos, obj) {
        var t = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'],
            i, j, str, arrStr, 
            start, len, len2,
            arr, mat;
            
        // Take the first transformation matrix
        len = t.length;
        for (i=0, str=''; i<len; i++) {
            if (JXG.exists(obj.style[t[i]])) {
                str = obj.style[t[i]];
                break;
            }
        }

        /**
        * Extract the coordinates and apply the transformation
        * to cPos
        */
        if (str!='') {
            start = str.indexOf('(');
            if (start>0) {
                len = str.length;
                arrstr = str.substring(start+1,len-1);
                arr = arrstr.split(',');
                for (j=0, len2=arr.length; j<len2; j++) {
                    arr[j] = parseFloat(arr[j]);
                }
            
                if (0==str.indexOf('matrix')) {    
                    mat = [[arr[0], arr[1]],
                           [arr[2], arr[3]]];
                    //cPos = JXG.Math.matVecMult(mat, cPos);
                    cPos[0] += arr[4];
                    cPos[1] += arr[5];
                } else if (0==str.indexOf('translateX')) {    
                    cPos[0] += arr[0];
                } else if (0==str.indexOf('translateY')) {    
                    cPos[1] += arr[0];
                } else if (0==str.indexOf('translate')) {    
                    cPos[0] += arr[0];
                    cPos[1] += arr[1];
                // The following trannsformations do not work
                // and require more tests.
                // Missing are rotate, skew, skewX, skewY
                } else if (0==str.indexOf('scaleX')) {    
                    mat = [[arr[0], 0],
                           [0, 1]];
                    cPos = JXG.Math.matVecMult(mat, cPos);
                } else if (0==str.indexOf('scaleY')) {    
                    mat = [[1, 0],
                           [0, arr[0]]];
                    cPos = JXG.Math.matVecMult(mat, cPos);
                } else if (0==str.indexOf('scale')) {    
                    mat = [[arr[0], 0],
                           [0, arr[1]]];
                    cPos = JXG.Math.matVecMult(mat, cPos);
                }
            }
        }
        return cPos;
    },

    /**
     * TODO
     */
    getCSSTransformMatrix: function(obj) {
        var t = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'],
            i, j, str, arrStr, 
            start, len, len2,
            arr, mat;

        mat = [[1, 0, 0],
               [0, 1, 0],
               [0, 0, 1]];
               
       // Take the first transformation matrix
        len = t.length;
        for (i=0, str=''; i<len; i++) {
            if (JXG.exists(obj.style[t[i]])) {
                str = obj.style[t[i]];
                break;
            }
        }
        
        if (str!='') {
            start = str.indexOf('(');
            if (start>0) {
                len = str.length;
                arrstr = str.substring(start+1,len-1);
                arr = arrstr.split(',');
                for (j=0, len2=arr.length; j<len2; j++) {
                    arr[j] = parseFloat(arr[j]);
                }
            
                if (0==str.indexOf('matrix')) {  
                    mat = [[1, 0, 0],
                           [arr[4], arr[0], arr[1]],
                           [arr[5], arr[2], arr[3]]];
                } else if (0==str.indexOf('translateX')) {    
                    mat[1][0] = arr[0];
                } else if (0==str.indexOf('translateY')) {    
                    mat[2][0] = arr[0];
                } else if (0==str.indexOf('translate')) {    
                    mat[1][0] = arr[0];
                    mat[2][0] = arr[1];
                // Missing are rotate, skew, skewX, skewY
                } else if (0==str.indexOf('scaleX')) { 
                    mat[1][1] = arr[0];
                } else if (0==str.indexOf('scaleY')) {    
                    mat[2][2] = arr[0];
                } else if (0==str.indexOf('scale')) {    
                    mat[1][1] = arr[0];
                    mat[2][2] = arr[1];
                }
            }
        }
        return mat;
    },
    
    /**
     * Extracts the keys of a given object.
     * @param object The object the keys are to be extracted
     * @param onlyOwn If true, hasOwnProperty() is used to verify that only keys are collected
     * the object owns itself and not some other object in the prototype chain.
     * @returns {Array} All keys of the given object.
     */
    keys: function (object, onlyOwn) {
        var keys = [], property;

        for (property in object) {
            if (onlyOwn) {
                if (object.hasOwnProperty(property)) {
                    keys.push(property);
                }
            } else {
                keys.push(property);
            }
        }
        return keys;
    },

    /**
     * Search an array for a given value.
     * @param {Array} array
     * @param {%} value
     * @param {String} sub Use this property if the elements of the array are objects.
     * @returns {Number} The index of the first appearance of the given value, or
     * <tt>-1</tt> if the value was not found.
     */
    indexOf: function (array, value, sub) {
        var i, s = JXG.exists(sub);

        if (Array.indexOf && !s) {
            return array.indexOf(value);
        }

        for (i = 0; i < array.length; i++) {
            if ((s && array[i][sub] === value) || (!s && array[i] === value)) {
                return i;
            }
        }

        return -1;
    },

    /**
     * Replaces all occurences of &amp; by &amp;amp;, &gt; by &amp;gt;, and &lt; by &amp;lt;.
     * @param str
     */
    escapeHTML: function (str) {
        return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
    },

    /**
     * Eliminates all substrings enclosed by &lt; and &gt; and replaces all occurences of
     * &amp;amp; by &amp;, &amp;gt; by &gt;, and &amp;lt; by &lt;.
     * @param str
     */
    unescapeHTML: function (str) {
        return str.replace(/<\/?[^>]+>/gi, '').replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
    },

    /**
     * This outputs an object with a base class reference to the given object. This is useful if
     * you need a copy of an e.g. attributes object and want to overwrite some of the attributes
     * without changing the original object.
     * @param {Object} obj Object to be embedded.
     * @returns {Object} An object with a base class reference to <tt>obj</tt>.
     */
    clone: function (obj) {
        var cObj = {};
        cObj.prototype = obj;
        return cObj;
    },

    /**
     * Embeds an existing object into another one just like {@link #clone} and copies the contents of the second object
     * to the new one. Warning: The copied properties of obj2 are just flat copies.
     * @param {Object} obj Object to be copied.
     * @param {Object} obj2 Object with data that is to be copied to the new one as well.
     * @returns {Object} Copy of given object including some new/overwritten data from obj2.
     */
    cloneAndCopy: function (obj, obj2) {
        var cObj = function(){}, r;
        cObj.prototype = obj;
        //cObj = obj;
        for(r in obj2)
            cObj[r] = obj2[r];

        return cObj;
    },

    /**
     * Creates a deep copy of an existing object, i.e. arrays or sub-objects are copied component resp.
     * element-wise instead of just copying the reference. If a second object is supplied, the two objects
     * are merged into one object. The properties of the second object have priority.
     * @param {Object} obj This object will be copied.
     * @param {Object} obj2 This object will merged into the newly created object
     * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes
     * @returns {Object} copy of obj or merge of obj and obj2.
     */
    deepCopy: function (obj, obj2, toLower) {
        var c, i, prop, j, i2;

        toLower = toLower || false;

        if (typeof obj !== 'object' || obj == null) {
            return obj;
        }

        if (this.isArray(obj)) {
            c = [];
            for (i = 0; i < obj.length; i++) {
                prop = obj[i];
                if (typeof prop == 'object') {
                    c[i] = this.deepCopy(prop);
                } else {
                    c[i] = prop;
                }
            }
        } else {
            c = {};
            for (i in obj) {
                i2 = toLower ? i.toLowerCase() : i;

                prop = obj[i];
                if (typeof prop == 'object') {
                    c[i2] = this.deepCopy(prop);
                } else {
                    c[i2] = prop;
                }
            }

            for (i in obj2) {
                i2 = toLower ? i.toLowerCase() : i;

                prop = obj2[i];
                if (typeof prop == 'object') {
                    if (JXG.isArray(prop) || !JXG.exists(c[i2])) {
                        c[i2] = this.deepCopy(prop);
                    } else {
                        c[i2] = this.deepCopy(c[i2], prop, toLower);
                    }
                } else {
                    c[i2] = prop;
                }
            }
        }
        return c;
    },

    /**
     * Converts a JavaScript object into a JSON string.
     * @param {Object} obj A JavaScript object, functions will be ignored.
     * @param {Boolean} [noquote=false] No quotes around the name of a property.
     * @returns {String} The given object stored in a JSON string.
     */
    toJSON: function (obj, noquote) {
        var s, val;

        noquote = JXG.def(noquote, false);

        // check for native JSON support:
        if (window.JSON && window.JSON.stringify && !noquote) {
            try {
                s = JSON.stringify(obj);
                return s;
            } catch(e) {
                // if something goes wrong, e.g. if obj contains functions we won't return
                // and use our own implementation as a fallback
            }
        }

        switch (typeof obj) {
            case 'object':
                if (obj) {
                    var list = [];
                    if (obj instanceof Array) {
                        for (var i=0;i < obj.length;i++) {
                            list.push(JXG.toJSON(obj[i], noquote));
                        }
                        return '[' + list.join(',') + ']';
                    } else {
                        for (var prop in obj) {

                            try {
                                val = JXG.toJSON(obj[prop], noquote);
                            } catch (e) {
                                val = '';
                            }

                            if (noquote) {
                                list.push(prop + ':' + val);
                            } else {
                                list.push('"' + prop + '":' + val);
                            }
                        }
                        return '{' + list.join(',') + '} ';
                    }
                } else {
                    return 'null';
                }
            case 'string':
                return '\'' + obj.replace(/(["'])/g, '\\$1') + '\'';
            case 'number':
            case 'boolean':
                return new String(obj);
        }
    },

    /**
     * Makes a string lower case except for the first character which will be upper case.
     * @param {String} str Arbitrary string
     * @returns {String} The capitalized string.
     */
    capitalize: function (str) {
        return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();
    },

    /**
     * Process data in timed chunks. Data which takes long to process, either because it is such
     * a huge amount of data or the processing takes some time, causes warnings in browsers about
     * irresponsive scripts. To prevent these warnings, the processing is split into smaller pieces
     * called chunks which will be processed in serial order.
     * Copyright 2009 Nicholas C. Zakas. All rights reserved. MIT Licensed
     * @param {Array} items to do
     * @param {Function} process Function that is applied for every array item
     * @param {Object} context The scope of function process
     * @param {Function} callback This function is called after the last array element has been processed.
     */
    timedChunk: function (items, process, context, callback) {
        var todo = items.concat();   //create a clone of the original
        setTimeout(function (){
            var start = +new Date();
            do {
                process.call(context, todo.shift());
            } while (todo.length > 0 && (+new Date() - start < 300));
            if (todo.length > 0){
                setTimeout(arguments.callee, 1);
            } else {
                callback(items);
            }
        }, 1);
    },

    /**
     * Make numbers given as strings nicer by removing all unnecessary leading and trailing zeroes.
     * @param {String} str
     * @returns {String}
     */
    trimNumber: function (str) {
        str = str.replace(/^0+/, "");
        str = str.replace(/0+$/, "");
        if (str[str.length-1] == '.' || str[str.length-1] == ',') {
            str = str.slice(0, -1);
        }
        if (str[0] == '.' || str[0] == ',') {
            str = "0" + str;
        }

        return str;
    },

    /**
     * Remove all leading and trailing whitespaces from a given string.
     * @param {String} str
     * @returns {String}
     */
    trim: function (str) {
        str = str.replace(/^\s+/, "");
        str = str.replace(/\s+$/, "");

        return str;
    },

    /**
     * If <tt>val</tt> is a function, it will be evaluated without giving any parameters, else the input value
     * is just returned.
     * @param val Could be anything. Preferably a number or a function.
     * @returns If <tt>val</tt> is a function, it is evaluated and the result is returned. Otherwise <tt>val</tt> is returned.
     */
    evaluate: function (val) {
        if (JXG.isFunction(val)) {
            return val();
        } else {
            return val;
        }
    },

    /**
     * Eliminates duplicate entries in an array.
     * @param {Array} a An array
     * @returns {Array} The array with duplicate entries eliminated.
     */
    eliminateDuplicates: function (a) {
        var i, len = a.length,
            result = [],
            obj = {};

        for (i = 0; i < len; i++) {
            obj[a[i]] = 0;
        }

        for (i in obj) {
            if (obj.hasOwnProperty(i)) {
                result.push(i);
            }
        }

        return result;
    },

    /**
     * Compare two arrays.
     * @param {Array} a1
     * @param {Array} a2
     * @returns {Boolean} <tt>true</tt>, if the arrays coefficients are of same type and value.
     */
    cmpArrays: function (a1, a2) {
        var i;

        // trivial cases
        if (a1 === a2) {
            return true;
        }

        if (a1.length !== a2.length) {
            return false;
        }

        for (i = 0; i < a1.length; i++) {
            if ((typeof a1[i] !== typeof a2[i]) || (a1[i] !== a2[i])) {
                return false;
            }
        }

        return true;
    },

    /**
     * Truncate a number <tt>n</tt> after <tt>p</tt> decimals.
     * @param n
     * @param p
     * @returns {Number}
     */
    trunc: function (n, p) {
        p = JXG.def(p, 0);

        if (p == 0) {
            n = ~~n;
        } else {
            n = n.toFixed(p);
        }

        return n;
    },

    /**
     * Truncate a number <tt>val</tt> automatically.
     * @param val
     * @returns {Number}
     */
    autoDigits: function(val) {
        var x = Math.abs(val);
        if (x>0.1) {
            x = val.toFixed(2);
        } else if (x>=0.01) {
            x = val.toFixed(4);
        } else if (x>=0.0001) {
            x = val.toFixed(6);
        } else {
            x = val;
        }
        return x;
    },

    /**
     * Add something to the debug log. If available a JavaScript debug console is used. Otherwise
     * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted.
     * @param {%} An arbitrary number of parameters.
     */
    debug: function (s) {
        var i;

        for(i = 0; i < arguments.length; i++) {
            s = arguments[i];
            if (window.console && console.log) {
                //if (typeof s === 'string') s = s.replace(/<\S[^><]*>/g, "");
                console.log(s);
            } else if (document.getElementById('debug')) {
                document.getElementById('debug').innerHTML += s + "<br/>";
            }
            // else: do nothing
        }
    },

    debugWST: function (s) {
        var e;
        JXG.debug(s);

        if (window.console && console.log) {
            e = new Error();
            if (e && e.stack) {
                console.log('stacktrace');
                console.log(e.stack.split('\n').slice(1).join('\n'));
            }
        }
    },

    /**
     * Generates a deep copy of an array and removes the duplicate entries.
     * @param {Array} arr
     * @returns {Array}
     */
    uniqueArray: function(arr) {
        var i, j, isArray, ret = [];

        if (arr.length === 0) {
            return [];
        }

        isArray = JXG.isArray(arr[0]);

        for (i=0; i<arr.length; i++) {
            for (j=i+1; j<arr.length; j++) {
                if (isArray && JXG.cmpArrays(arr[i], arr[j])) {
                    arr[i] = [];
                } else if (!isArray && arr[i] === arr[j]) {
                    arr[i] = '';
                }
            }
        }

        j = 0;

        for (i=0; i<arr.length; i++) {
            if (!isArray && arr[i] !== "") {
                ret[j] = arr[i];
                j++;
            } else if (isArray && arr[i].length !== 0) {
                ret[j] = (arr[i].slice(0));
                j++;
            }
        }

        return ret;
    },

    /**
     * Checks if an array contains an element equal to <tt>val</tt> but does not check the type!
     * @param {Array} arr
     * @param {%} val
     * @returns {Boolean}
     */
    isInArray: function(arr, val) {
        var i;

        for (i=0; i<arr.length; i++) {
            if (arr[i] == val) {
                return true;
            }
        }

        return false;
    },

    /**
     * Tests if the input variable is an Array
     * @param input
     */
    isArray2: function(input) {
        return typeof(input) == 'object' && (input instanceof Array);
    },

    /**
     * Tests if the input variable is an Object
     * @param input
     */
    isObject: function(input) {
        return typeof(input) == 'object' && (input instanceof Object) && !(input instanceof Array);
    },

    /**
     * Checks if an object contains a key, whose value equals to val
     */
    isInObject: function(lit, val) {

        for (var el in lit)
            if (lit.hasOwnProperty(el))
                if (lit[el] == val)
                    return true;

        return false;
    },

    collectionContains: function(arr, val) {

        if (JXG.isArray2(arr))
            return JXG.isInArray(arr, val);
        else if (JXG.isObject(arr))
            return JXG.isInObject(arr, val);
        else
            return arr == val;
    }
});

// JessieScript startup: Search for script tags of type text/jessiescript and interpret them.
if (typeof window === 'object' && typeof document === 'object') {
    JXG.addEvent(window, 'load', function () {
        var scripts = document.getElementsByTagName('script'), type,
            i, j, div, board, width, height, bbox, axis, grid, code;

        for(i=0;i<scripts.length;i++) {
            type = scripts[i].getAttribute('type', false);
            if (!JXG.exists(type)) continue;
            if (type.toLowerCase() === 'text/jessiescript' || type.toLowerCase() === 'jessiescript' || type.toLowerCase() === 'text/jessiecode' || type.toLowerCase() === 'jessiecode') {
                width = scripts[i].getAttribute('width', false) || '500px';
                height = scripts[i].getAttribute('height', false) || '500px';
                bbox = scripts[i].getAttribute('boundingbox', false) || '-5, 5, 5, -5';
                bbox = bbox.split(',');
                if (bbox.length!==4) {
                    bbox = [-5, 5, 5, -5];
                } else {
                    for(j=0;j<bbox.length;j++) {
                        bbox[j] = parseFloat(bbox[j]);
                    }
                }
                axis = JXG.str2Bool(scripts[i].getAttribute('axis', false) || 'false');
                grid = JXG.str2Bool(scripts[i].getAttribute('grid', false) || 'false');

                div = document.createElement('div');
                div.setAttribute('id', 'jessiescript_autgen_jxg_'+i);
                div.setAttribute('style', 'width:'+width+'; height:'+height+'; float:left');
                div.setAttribute('class', 'jxgbox');
                try {
                    document.body.insertBefore(div, scripts[i]);
                } catch (e) {
                    // there's probably jquery involved...
                    if (typeof jQuery !== 'undefined') {
                        jQuery(div).insertBefore(scripts[i]);
                    }
                }

                if (document.getElementById('jessiescript_autgen_jxg_' + i)) {
                    board = JXG.JSXGraph.initBoard('jessiescript_autgen_jxg_' + i, {boundingbox: bbox, keepaspectratio:true, grid: grid, axis: axis});

                    code = scripts[i].innerHTML;
                    code = code.replace(/<!\[CDATA\[/g, '').replace(/\]\]>/g, '');
                    scripts[i].innerHTML = code;
                    if (type.toLowerCase().indexOf('script') > -1) {
                        board.construct(code);
                    } else {
                        try {
                            board.jc.parse(code);
                        } catch (e) {
                            JXG.debug(e);
                        }
                    }
                } else {
                    JXG.debug('JSXGraph: Apparently the div injection failed. Can\'t create a board, sorry.');
                }
            }
        }
    }, window);
}


/* 
    Copyright 2012
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/** 
 * @fileoverview In this file the EventEmitter interface is defined.
 */

/**
 * @namespace
 */
JXG.EventEmitter = {
    /**
     * Holds the registered event handlers.
     * @name JXG.EventEmitter#eventHandlers
     * @type Object
     */
    eventHandlers: {},
    
    /**
     * Triggers all event handlers of this element for a given event.
     * @name JXG.EventEmitter#triggerEventHandlers
     * @function
     * @param {String} event
     * @returns Reference to the object.
     */
    triggerEventHandlers: function (event) {
        var i, h, args = Array.prototype.slice.call(arguments, 1),
            j, evt, len1, len2;

        if (!JXG.isArray(event)) {
            event = [event];
        }

        len1 = event.length;
        for (j = 0; j < len1; j++) {
            evt = event[j];
            if (JXG.isArray(this.eventHandlers[evt])) {
                len2 = this.eventHandlers[evt].length;
                for (i = 0; i < len2; i++) {
                    h = this.eventHandlers[evt][i];
                    h.handler.apply(h.context, args);
                }
            }
        }
        
        return this;
    },

    /**
     * Register a new event handler. For a list of possible events see documentation of the elements and objects implementing
     * the {@link EventEmitter} interface.
     * @name JXG.EventEmitter#on
     * @function
     * @param {String} event
     * @param {Function} handler
     * @param {Object} [context] The context the handler will be called in, default is the element itself.
     * @returns Reference to the object.
     */
    on: function (event, handler, context) {
        if (!JXG.isArray(this.eventHandlers[event])) {
            this.eventHandlers[event] = [];
        }

        context = JXG.def(context, this);

        this.eventHandlers[event].push({
            handler: handler,
            context: context
        });
        
        return this;
    },

    /**
     * Unregister an event handler.
     * @name JXG.EventEmitter#off
     * @function
     * @param {String} event
     * @param {Function} handler
     * @returns Reference to the object.
     */
    off: function (event, handler) {
        var i;

        if (!event || !JXG.isArray(this.eventHandlers[event])) {
            return this;
        }

        if (handler) {
            i = JXG.indexOf(this.eventHandlers[event], handler, 'handler');
            if (i > -1) {
                this.eventHandlers[event].splice(i, 1);
            }
        } else {
            this.eventHandlers[event].length = 0;
        }
        
        return this;
    },

    /**
     * @description Implements the functionality from this interface in the given object. All objects getting their event handling
     * capabilities from this method should document it by adding the <tt>on, off, triggerEventHandlers</tt> via the
     * borrows tag as methods to their documentation: <pre>@borrows JXG.EventEmitter#on as this.on</pre>
     * @name JXG.EventEmitter#eventify
     * @function
     * @param {Object} o
     */
    eventify: function (o) {
        o.eventHandlers = {};
        o.on = this.on;
        o.off = this.off;
        o.triggerEventHandlers = this.triggerEventHandlers;
    }
};


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview In this file the namespace JXG.Math is defined, which is the base namespace
 * for namespaces like Math.Numerics, Math.Algebra, Math.Statistics etc.
 * @author graphjs
 */

/**
 * Math namespace.
 * @namespace
 */
JXG.Math = (function(JXG, Math, undefined) {

    /*
     * Dynamic programming approach for recursive functions.
     * From "Speed up your JavaScript, Part 3" by Nicholas C. Zakas.
     * @see JXG.Math.factorial
     * @see JXG.Math.binomial
     * http://blog.thejit.org/2008/09/05/memoization-in-javascript/
     *
     * This method is hidden, because it is only used in JXG.Math. If someone wants
     * to use it in JSXGraph outside of JXG.Math, it should be moved to jsxgraph.js
     */
    var memoizer = function (f) {
        var cache, join;

        if (f.memo) {
            return f.memo;
        }
        cache = {};
        join = Array.prototype.join;

        return (f.memo = function() {
            var key = join.call(arguments);

            return (cache[key] !== undefined) // Seems to be a bit faster than "if (a in b)"
                ? cache[key]
                : cache[key] = f.apply(this, arguments);
        });
    };

    /** @lends JXG.Math */
    return {
        /**
         * eps defines the closeness to zero. If the absolute value of a given number is smaller
         * than eps, it is considered to be equal to zero.
         * @type number
         */
        eps: 0.000001,

        /**
         * The JavaScript implementation of the % operator returns the symmetric modulo.
         * They are both identical if a >= 0 and m >= 0 but the results differ if a or m < 0.
         * @param {Number} a
         * @param {Number} m
         * @returns Mathematical modulo <tt>a mod m</tt>
         */
        mod: function (a, m) {
            return a - Math.floor(a/m)*m;
        },

        /**
         * Initializes a vector as an array with the coefficients set to the given value resp. zero.
         * @param {Number} n Length of the vector
         * @param {Number} [init=0] Initial value for each coefficient
         * @returns {Array} A <tt>n</tt> times <tt>m</tt>-matrix represented by a
         * two-dimensional array. The inner arrays hold the columns, the outer array holds the rows.
         */
        vector: function(n, init) {
            var r, i;

            init = init || 0;

            r = new Array(Math.ceil(n));
            for(i=0; i<n; i++) {
                r[i] = init;
            }

            return r;
        },

        /**
         * Initializes a matrix as an array of rows with the given value.
         * @param {Number} n Number of rows
         * @param {Number} [m=n] Number of columns
         * @param {Number} [init=0] Initial value for each coefficient
         * @returns {Array} A <tt>n</tt> times <tt>m</tt>-matrix represented by a
         * two-dimensional array. The inner arrays hold the columns, the outer array holds the rows.
         */
        matrix: function(n, m, init) {
            var r, i, j;

            init = init || 0;
            m = m || n;

            r = new Array(Math.ceil(n));
            for(i=0; i<n; i++) {
                r[i] = new Array(Math.ceil(m));
                for(j=0; j<m; j++) {
                    r[i][j] = init;
                }
            }

            return r;
        },

        /**
         * Generates an identity matrix. If n is a number and m is undefined or not a number, a square matrix is generated,
         * if n and m are both numbers, an nxm matrix is generated.
         * @param {Number} n Number of rows
         * @param {Number} [m=n] Number of columns
         * @returns {Array} A square matrix of length <tt>n</tt> with all coefficients equal to 0 except a_(i,i), i out of (1, ..., n), if <tt>m</tt> is undefined or not a number
         * or a <tt>n</tt> times <tt>m</tt>-matrix with a_(i,j) = 0 and a_(i,i) = 1 if m is a number.
         */
        identity: function(n, m) {
            var r, i;

            if((m === undefined) && (typeof m !== 'number')) {
                m = n;
            }

            r = this.matrix(n, m);
            for(i=0; i<Math.min(n, m); i++) {
                r[i][i] = 1;
            }

            return r;
        },

        /**
         * Generates a 4x4 matrix for 3D to 2D projections.
         * @param {Number} l Left
         * @param {Number} r Right
         * @param {Number} t Top
         * @param {Number} b Bottom
         * @param {Number} n Near
         * @param {Number} f Far
         * @returns {Array} 4x4 Matrix
         */
        frustum: function (l, r, b, t, n, f) {
            var ret = JXG.Math.matrix(4, 4);

            ret[0][0] = (n*2) / (r - l);
            ret[0][1] = 0;
            ret[0][2] = (r + l) / (r - l);
            ret[0][3] = 0;

            ret[1][0] = 0;
            ret[1][1] = (n*2) / (t - b);
            ret[1][2] = (t + b) / (t - b);
            ret[1][3] = 0;

            ret[2][0] = 0;
            ret[2][1] = 0;
            ret[2][2] = -(f + n) / (f - n);
            ret[2][3] = -(f*n*2) / (f - n);

            ret[3][0] = 0;
            ret[3][1] = 0;
            ret[3][2] = -1;
            ret[3][3] = 0;

            return ret;
        },

        /**
         * Generates a 4x4 matrix for 3D to 2D projections.
         * @param {Number} fov Field of view in vertical direction, given in rad.
         * @param {Number} ratio Aspect ratio of the projection plane.
         * @param {Number} n Near
         * @param {Number} f Far
         * @returns {Array} 4x4 Projection Matrix
         */
        projection: function (fov, ratio, n, f) {
            var t = n*Math.tan(fov/2),
                r = t*ratio;
            return this.frustum(-r, r, -t, t, n, f);
        },

        /**
         * Multiplies a vector vec to a matrix mat: mat * vec. The matrix is interpreted by this function as an array of rows. Please note: This
         * function does not check if the dimensions match.
         * @param {Array} mat Two dimensional array of numbers. The inner arrays describe the columns, the outer ones the matrix' rows.
         * @param {Array} vec Array of numbers
         * @returns {Array} Array of numbers containing the result
         * @example
         * var A = [[2, 1],
         *          [1, 3]],
         *     b = [4, 5],
         *     c;
         * c = JXG.Math.matVecMult(A, b)
         * // c === [13, 19];
         */
        matVecMult: function(mat, vec) {
            var m = mat.length,
                n = vec.length,
                res = [],
                i, s, k;

            if (n===3) {
                for (i=0;i<m;i++) {
                    res[i] = mat[i][0]*vec[0] + mat[i][1]*vec[1] + mat[i][2]*vec[2];
                }
            } else {
                for (i=0;i<m;i++) {
                    s = 0;
                    for (k=0;k<n;k++) { s += mat[i][k]*vec[k]; }
                    res[i] = s;
                }
            }
            return res;
        },

        /**
         * Computes the product of the two matrices mat1*mat2.
         * @param {Array} mat1 Two dimensional array of numbers
         * @param {Array} mat2 Two dimensional array of numbers
         * @returns {Array} Two dimensional Array of numbers containing result
         */
        matMatMult: function(mat1, mat2) {
            var m = mat1.length,
                n = m>0 ? mat2[0].length : 0,
                m2 = mat2.length,
                res = this.matrix(m,n),
                i, j, s, k;

            for (i=0;i<m;i++) {
                for (j=0;j<n;j++) {
                    s = 0;
                    for (k=0;k<m2;k++) {
                        s += mat1[i][k]*mat2[k][j];
                    }
                    res[i][j] = s;
                }
            }
            return res;
        },

        /**
         * Transposes a matrix given as a two dimensional array.
         * @param {Array} M The matrix to be transposed
         * @returns {Array} The transpose of M
         */
        transpose: function(M) {
            var MT, i, j,
                m, n;

            m = M.length;                     // number of rows of M
            n = M.length>0 ? M[0].length : 0; // number of columns of M
            MT = this.matrix(n,m);

            for (i=0; i<n; i++) {
                for (j=0;j<m;j++) {
                    MT[i][j] = M[j][i];
                }
            }
            return MT;
        },

        /**
         * Compute the inverse of an nxn matrix with Gauss elimination.
         * @param {Array} Ain
         * @returns {Array} Inverse matrix of Ain
         */
        inverse: function(Ain) {
            var i,j,k,s,ma,r,swp,
                n = Ain.length,
                A = [],
                p = [],
                hv = [];

            for (i=0;i<n;i++) {
                A[i] = [];
                for (j=0;j<n;j++) { A[i][j] = Ain[i][j]; }
                p[i] = i;
            }

            for (j=0;j<n;j++) {
                // pivot search:
                ma = Math.abs(A[j][j]);
                r = j;
                for (i=j+1;i<n;i++) {
                    if (Math.abs(A[i][j])>ma) {
                        ma = Math.abs(A[i][j]);
                        r = i;
                    }
                }
                if (ma<=JXG.Math.eps) { // Singular matrix
                    return false;
                }
                // swap rows:
                if (r>j) {
                    for (k=0;k<n;k++) {
                        swp = A[j][k]; A[j][k] = A[r][k]; A[r][k] = swp;
                    }
                    swp = p[j]; p[j] = p[r]; p[r] = swp;
                }
                // transformation:
                s = 1.0/A[j][j];
                for (i=0;i<n;i++) {
                    A[i][j] *= s;
                }
                A[j][j] = s;
                for (k=0;k<n;k++) if (k!=j) {
                    for (i=0;i<n;i++) if (i!=j) {
                        A[i][k] -= A[i][j]*A[j][k];
                    }
                    A[j][k] = -s*A[j][k];
                }
            }
            // swap columns:
            for (i=0;i<n;i++) {
                for (k=0;k<n;k++) { hv[p[k]] = A[i][k]; }
                for (k=0;k<n;k++) { A[i][k] = hv[k]; }
            }
            return A;
        },

        /**
         * Inner product of two vectors a and b. n is the length of the vectors.
         * @param {Array} a Vector
         * @param {Array} b Vector
         * @param {Number} [n] Length of the Vectors. If not given the length of the first vector is taken.
         * @returns {Number} The inner product of a and b.
         */
        innerProduct: function(a, b, n) {
            var i, s = 0;

            if((n === undefined) || (typeof n !== 'number')) {
                n = a.length;
            }

            for (i=0; i<n; i++) {
                s += a[i]*b[i];
            }

            return s;
        },

        /**
         * Calculates the cross product of two vectors both of length three.
         * In case of homogeneous coordinates this is either
         * <ul>
         * <li>the intersection of two lines</li>
         * <li>the line through two points</li>
         * </ul>
         * @param {Array} c1 Homogeneous coordinates of line or point 1
         * @param {Array} c2 Homogeneous coordinates of line or point 2
         * @returns {Array} vector of length 3: homogeneous coordinates of the resulting point / line.
         */
        crossProduct: function(c1,c2) {
            return [c1[1]*c2[2]-c1[2]*c2[1],
                c1[2]*c2[0]-c1[0]*c2[2],
                c1[0]*c2[1]-c1[1]*c2[0]];
        },

        /**
         * Compute the factorial of a positive integer. If a non-integer value
         * is given, the fraction will be ignored.
         * @function
         * @param {Number} n
         * @returns {Number} n! = n*(n-1)*...*2*1
         */
        factorial: memoizer(function (n) {
            if (n<0) return NaN;
            n = Math.floor(n);
            if (n===0 || n===1) return 1;
            return n*arguments.callee(n-1);
        }),

        /**
         * Computes the binomial coefficient n over k.
         * @function
         * @param {Number} n Fraction will be ignored
         * @param {Number} k Fraction will be ignored
         * @returns {Number} The binomial coefficient n over k
         */
        binomial: memoizer(function(n,k) {
            var b, i;

            if (k>n || k<0) return NaN;

            k = Math.round(k);
            n = Math.round(n);

            if (k===0 || k===n) return 1;

            b = 1;
            for (i=0; i<k; i++) {
                b *= (n-i);
                b /= (i+1);
            }

            return b;
        }),

        /**
         * Calculates the cosine hyperbolicus of x.
         * @param {Number} x The number the cosine hyperbolicus will be calculated of.
         * @returns {Number} Cosine hyperbolicus of the given value.
         */
        cosh: function(x) {
            return (Math.exp(x)+Math.exp(-x))*0.5;
        },

        /**
         * Sine hyperbolicus of x.
         * @param {Number} x The number the sine hyperbolicus will be calculated of.
         * @returns {Number} Sine hyperbolicus of the given value.
         */
        sinh: function(x) {
            return (Math.exp(x)-Math.exp(-x))*0.5;
        },

        /**
         * Compute base to the power of exponent.
         * @param {Number} base
         * @param {Number} exponent
         * @returns {Number} base to the power of exponent.
         */
        pow: function(base, exponent) {
            if (base===0) {
                if (exponent===0) {
                    return 1;
                } else {
                    return 0;
                }
            }

            if (Math.floor(exponent)===exponent) {// a is an integer
                return Math.pow(base,exponent);
            } else { // a is not an integer
                if (base>0) {
                    return Math.exp(exponent*Math.log(Math.abs(base)));
                } else {
                    return NaN;
                }
            }
        },

        /**
         * A square & multiply algorithm to compute base to the power of exponent.
         * Implementated by Wolfgang Riedl.
         * @param {Number} base
         * @param {Number} exponent
         * @returns {Number} Base to the power of exponent
         */
        squampow: function(base, exponent) {
            var result;

            if (Math.floor(exponent)===exponent) { // exponent is integer (could be zero)
                result = 1;
                if(exponent < 0) {
                    // invert: base
                    base = 1.0 / base;
                    exponent *= -1;
                }
                while(exponent != 0) {
                    if(exponent & 1)
                        result *= base;
                    exponent >>= 1;
                    base *= base;
                }
                return result;
            } else {
                return this.pow(base, exponent);
            }
        },

        /**
         * Normalize the standard form [c, b0, b1, a, k, r, q0, q1].
         * @private
         * @param {Array} stdform The standard form to be normalized.
         * @returns {Array} The normalized standard form.
         */
        normalize: function(stdform) {
            var a2 = 2*stdform[3],
                r = stdform[4]/(a2),  // k/(2a)
                n, signr;
            stdform[5] = r;
            stdform[6] = -stdform[1]/a2;
            stdform[7] = -stdform[2]/a2;
            if (r===Infinity || isNaN(r)) {
                n = Math.sqrt(stdform[1]*stdform[1]+stdform[2]*stdform[2]);
                stdform[0] /= n;
                stdform[1] /= n;
                stdform[2] /= n;
                stdform[3] = 0;
                stdform[4] = 1;
            } else if (Math.abs(r)>=1) {
                stdform[0] = (stdform[6]*stdform[6]+stdform[7]*stdform[7]-r*r)/(2*r);
                stdform[1] = -stdform[6]/r;
                stdform[2] = -stdform[7]/r;
                stdform[3] = 1/(2*r);
                stdform[4] = 1;
            } else {
                signr = (r<=0)?(-1):(1/*(r==0)?0:1*/);
                stdform[0] = signr*(stdform[6]*stdform[6]+stdform[7]*stdform[7]-r*r)*0.5;
                stdform[1] = -signr*stdform[6];
                stdform[2] = -signr*stdform[7];
                stdform[3] = signr/2;
                stdform[4] = signr*r;
            }
            return stdform;
        },

        /**
         * Converts a two dimensional array to a one dimensional Float32Array that can be processed by WebGL.
         * @param {Array} m A matrix in a two dimensional array.
         * @returns {Float32Array} A one dimensional array containing the matrix in column wise notation. Provides a fall
         * back to the default JavaScript Array if Float32Array is not available.
         */
        toGL: function (m) {

            var v, i, j;

            if(typeof Float32Array !== 'undefined') {
                v = new Float32Array(16);
            } else {
                v = new Array(16);
            }

            if (m.length !== 4 && m[0].length !== 4) {
                return v;
            }

            for (i = 0; i < 4; i++) {
                for (j = 0; j < 4; j++) {
                    v[i + 4*j] = m[i][j];
                }
            }

            return v;
        }

    };
})(JXG, Math);


/*
 Copyright 2008,2009
 Matthias Ehmann,
 Michael Gerhaeuser,
 Carsten Miller,
 Bianca Valentin,
 Alfred Wassermann,
 Peter Wilfahrt

 This file is part of JSXGraph.

 JSXGraph is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 JSXGraph is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @fileoverview In this file the namespace Math.Numerics is defined, which holds numerical
 * algorithms for solving linear equations etc.
 * @author graphjs
 */


/**
 * The JXG.Math.Numerics namespace holds numerical algorithms, constants, and variables.
 * @namespace
 */
JXG.Math.Numerics = (function(JXG, Math) {

    // Predefined butcher tableaus for the common Runge-Kutta method (fourth order), Heun method (second order), and Euler method (first order).
    var predefinedButcher = {
        rk4: {
            s: 4,
            A: [
                [ 0,  0,  0, 0],
                [0.5, 0,  0, 0],
                [ 0, 0.5, 0, 0],
                [ 0,  0,  1, 0]
            ],
            b: [1. / 6., 1. / 3., 1. / 3., 1. / 6.],
            c: [0, 0.5, 0.5, 1]
        },
        heun: {
            s: 2,
            A: [
                [0, 0],
                [1, 0]
            ],
            b: [0.5, 0.5],
            c: [0, 1]
        },
        euler: {
            s: 1,
            A: [
                [0]
            ],
            b: [1],
            c: [0]
        }
    };


    /** @lends JXG.Math.Numerics */
    return {

        /**
         * Solves a system of linear equations given by A and b using the Gauss-Jordan-elimination.
         * The algorithm runs in-place. I.e. the entries of A and b are changed.
         * @param {Array} A Square matrix represented by an array of rows, containing the coefficients of the lineare equation system.
         * @param {Array} b A vector containing the linear equation system's right hand side.
         * @throws {Error} If a non-square-matrix is given or if b has not the right length or A's rank is not full.
         * @returns {Array} A vector that solves the linear equation system.
         */
        Gauss: function(A, b) {
            var eps = JXG.Math.eps,
                // number of columns of A
                n = A.length > 0 ? A[0].length : 0,
                // copy the matrix to prevent changes in the original
                Acopy,
                // solution vector, to prevent changing b
                x,
                i, j, k,
                // little helper to swap array elements
                swap = function(i, j) {
                    var temp = this[i];

                    this[i] = this[j];
                    this[j] = temp;
                };

            if ((n !== b.length) || (n !== A.length))
                throw new Error("JXG.Math.Numerics.Gauss: Dimensions don't match. A must be a square matrix and b must be of the same length as A.");

            // initialize solution vector
            Acopy = new Array(n);
            x = b.slice(0, n);
            for (i = 0; i < n; i++) {
                Acopy[i] = A[i].slice(0, n);
            }

            // Gauss-Jordan-elimination
            for (j = 0; j < n; j++) {
                for (i = n - 1; i > j; i--) {
                    // Is the element which is to eliminate greater than zero?
                    if (Math.abs(Acopy[i][j]) > eps) {
                        // Equals pivot element zero?
                        if (Math.abs(Acopy[j][j]) < eps) {
                            // At least numerically, so we have to exchange the rows
                            swap.apply(Acopy, [i, j]);
                            swap.apply(x, [i, j]);
                        } else {
                            // Saves the L matrix of the LR-decomposition. unnecessary.
                            Acopy[i][j] /= Acopy[j][j];
                            // Transform right-hand-side b
                            x[i] -= Acopy[i][j] * x[j];
                            // subtract the multiple of A[i][j] / A[j][j] of the j-th row from the i-th.
                            for (k = j + 1; k < n; k ++) {
                                Acopy[i][k] -= Acopy[i][j] * Acopy[j][k];
                            }
                        }
                    }
                }
                if (Math.abs(Acopy[j][j]) < eps) { // The absolute values of all coefficients below the j-th row in the j-th column are smaller than JXG.Math.eps.
                    throw new Error("JXG.Math.Numerics.Gauss(): The given matrix seems to be singular.");
                }
            }
            this.backwardSolve(Acopy, x, true); // return Array

            return x;
        },

        /**
         * Solves a system of linear equations given by the right triangular matrix R and vector b.
         * @param {Array} R Right triangular matrix represented by an array of rows. All entries a_(i,j) with i &lt; j are ignored.
         * @param {Array} b Right hand side of the linear equation system.
         * @param {Boolean} [canModify=false] If true, the right hand side vector is allowed to be changed by this method.
         * @returns {Array} An array representing a vector that solves the system of linear equations.
         */
        backwardSolve: function(R, b, canModify) {
            var x, m, n, i, j;

            if (canModify) {
                x = b;
            } else {
                x = b.slice(0, b.length);
            }

            // m: number of rows of R
            // n: number of columns of R
            m = R.length;
            n = R.length > 0 ? R[0].length : 0;
            for (i = m - 1; i >= 0; i--) {
                for (j = n - 1; j > i; j--) {
                    x[i] -= R[i][j] * x[j];
                }
                x[i] /= R[i][i];
            }

            return x;
        },
        
        /**
         * @private
         * Gauss-Bareiss algorithm to compute the 
         * determinant of matrix without fractions.
         * See H. Cohen, "A course in computational
         * algebraic number thoery".
         */
        gaussBareiss: function(mat) {
            var k, c, s, i, j, p, n, M, t, 
                eps = JXG.Math.eps;
            
            n = mat.length;
            if (n<=0) { return 0; }
            if (mat[0].length<n) { n = mat[0].length; }
            
            // Copy the input matrix to M
            M = new Array(n);
            for (i = 0; i < n; i++) {
                M[i] = mat[i].slice(0, n);
            }
            
            c = 1;
            s = 1;
            for (k=0;k<n-1;k++) {
                p = M[k][k];
                if (Math.abs(p)<eps) {    // Pivot step
                    for (i=0;i<n;i++) {
                        if (Math.abs(M[i][k])>=eps) break
                    }
                    if (i==n) {      // No nonzero entry found in column k -> det(M) = 0
                        return 0.0;
                    } 
                    for (j=k;j<n;j++) {   // swap row i and k partially
                        t = M[i][j]; M[i][j] = M[k][j];  M[k][j] = t;
                    }
                    s = -s;
                    p = M[k][k];
                }
                
                // Main step
                for (i=k+1;i<n;i++) {
                    for (j=k+1;j<n;j++) {
                        t = p*M[i][j] - M[i][k]*M[k][j];
                        M[i][j] = t/c;
                    }
                }
                c = p;
            }
            return s*M[n-1][n-1];
        
        },

        /** 
         * Computes the determinant of a square nxn matrix with the
         * Gauss-Bareiss algorithm.
         * @param {Array} mat Matrix. 
         * @returns {Number} The determinant pf the matrix mat. 
                             The empty matrix returns 0.
         */ 
        det: function(mat) {
            var n = mat.length;
            if (n==2 && mat[0].length==2) {
                return mat[0][0]*mat[1][1] - mat[1][0]*mat[0][1];
            } else {
                return this.gaussBareiss(mat);
            }
        },
        
        /**
         * Compute the Eigenvalues and Eigenvectors of a symmetric 3x3 matrix with the Jacobi method
         * Adaption of a FORTRAN program by Ed Wilson, Dec. 25, 1990
         * @param {Array} Ain A symmetric 3x3 matrix.
         * @returns {Array} [A,V] the matrices A and V. The diagonal of A contains the Eigenvalues, V contains the Eigenvectors.
         */
        Jacobi: function(Ain) {
            var i,j,k,aa,si,co,tt,eps = JXG.Math.eps,
                sum = 0.0,
                ssum, amax,
                n = Ain.length,
                V = [
                    [0,0,0],
                    [0,0,0],
                    [0,0,0]
                ],
                A = [
                    [0,0,0],
                    [0,0,0],
                    [0,0,0]
                ], nloops=0;

            // Initialization. Set initial Eigenvectors.
            for (i = 0; i < n; i++) {
                for (j = 0; j < n; j++) {
                    V[i][j] = 0.0;
                    A[i][j] = Ain[i][j];
                    sum += Math.abs(A[i][j]);
                }
                V[i][i] = 1.0;
            }
            // Trivial problems
            if (n == 1) {
                return [A,V];
            }
            if (sum <= 0.0) {
                return [A,V];
            }

            sum /= (n * n);

            // Reduce matrix to diagonal
            do {
                ssum = 0.0;
                amax = 0.0;
                for (j = 1; j < n; j++) {
                    for (i = 0; i < j; i++) {
                        // Check if A[i][j] is to be reduced
                        aa = Math.abs(A[i][j]);
                        if (aa > amax) {
                            amax = aa;
                        }
                        ssum += aa;
                        if (aa >= eps) {
                            // calculate rotation angle
                            aa = Math.atan2(2.0 * A[i][j], A[i][i] - A[j][j]) * 0.5;
                            si = Math.sin(aa);
                            co = Math.cos(aa);
                            // Modify 'i' and 'j' columns
                            for (k = 0; k < n; k++) {
                                tt = A[k][i];
                                A[k][i] = co * tt + si * A[k][j];
                                A[k][j] = -si * tt + co * A[k][j];
                                tt = V[k][i];
                                V[k][i] = co * tt + si * V[k][j];
                                V[k][j] = -si * tt + co * V[k][j];
                            }
                            // Modify diagonal terms
                            A[i][i] = co * A[i][i] + si * A[j][i];
                            A[j][j] = -si * A[i][j] + co * A[j][j];
                            A[i][j] = 0.0;
                            // Make 'A' matrix symmetrical
                            for (k = 0; k < n; k++) {
                                A[i][k] = A[k][i];
                                A[j][k] = A[k][j];
                            }
                            // A[i][j] made zero by rotation
                        }
                    }
                }
                nloops++;
            } while (Math.abs(ssum) / sum > eps && nloops<2000);
            return [A,V];
        },

        /**
         * Calculates the integral of function f over interval using Newton-Cotes-algorithm.
         * @param {Array} interval The integration interval, e.g. [0, 3].
         * @param {function} f A function which takes one argument of type number and returns a number.
         * @param {object} [config={number_of_nodes:28,integration_type:'milne'}] The algorithm setup. Accepted properties are number_of_nodes of type number and integration_type
         * with value being either 'trapez', 'simpson', or 'milne'.
         * @returns {Number} Integral value of f over interval
         * @throws {Error} If config.number_of_nodes doesn't match config.integration_type an exception is thrown. If you want to use
         * simpson rule respectively milne rule config.number_of_nodes must be dividable by 2 respectively 4.
         * @example
         * function f(x) {
         *   return x*x;
         * }
         *
         * // calculates integral of <tt>f</tt> from 0 to 2.
         * var area1 = JXG.Math.Numerics.NewtonCotes([0, 2], f);
         *
         * // the same with an anonymous function
         * var area2 = JXG.Math.Numerics.NewtonCotes([0, 2], function (x) { return x*x; });
         *
         * // use trapez rule with 16 nodes
         * var area3 = JXG.Math.Numerics.NewtonCotes([0, 2], f,
         *                                   {number_of_nodes: 16, intergration_type: 'trapez'});
         */
        NewtonCotes: function(interval, f, config) {
            var integral_value = 0.0,
                number_of_nodes = config && typeof config.number_of_nodes === 'number' ? config.number_of_nodes : 28,
                available_types = {trapez: true, simpson: true, milne: true},
                integration_type = config && config.integration_type && available_types.hasOwnProperty(config.integration_type) && available_types[config.integration_type] ? config.integration_type : 'milne',
                step_size = (interval[1] - interval[0]) / number_of_nodes,
                evaluation_point, i, number_of_intervals;

            switch (integration_type) {
                case 'trapez':
                    integral_value = (f(interval[0]) + f(interval[1])) * 0.5;

                    evaluation_point = interval[0];
                    for (i = 0; i < number_of_nodes - 1; i++) {
                        evaluation_point += step_size;
                        integral_value += f(evaluation_point);
                    }
                    integral_value *= step_size;

                    break;
                case 'simpson':
                    if (number_of_nodes % 2 > 0) {
                        throw new Error("JSXGraph:  INT_SIMPSON requires config.number_of_nodes dividable by 2.");
                    }
                    number_of_intervals = number_of_nodes / 2.0;
                    integral_value = f(interval[0]) + f(interval[1]);
                    evaluation_point = interval[0];
                    for (i = 0; i < number_of_intervals - 1; i++) {
                        evaluation_point += 2.0 * step_size;
                        integral_value += 2.0 * f(evaluation_point);
                    }
                    evaluation_point = interval[0] - step_size;
                    for (i = 0; i < number_of_intervals; i++) {
                        evaluation_point += 2.0 * step_size;
                        integral_value += 4.0 * f(evaluation_point);
                    }
                    integral_value *= step_size / 3.0;
                    break;
                default:
                    if (number_of_nodes % 4 > 0) {
                        throw new Error("JSXGraph: Error in INT_MILNE: config.number_of_nodes must be a multiple of 4");
                    }
                    number_of_intervals = number_of_nodes * 0.25;
                    integral_value = 7.0 * (f(interval[0]) + f(interval[1]));
                    evaluation_point = interval[0];
                    for (i = 0; i < number_of_intervals - 1; i++) {
                        evaluation_point += 4.0 * step_size;
                        integral_value += 14.0 * f(evaluation_point);
                    }
                    evaluation_point = interval[0] - 3.0 * step_size;
                    for (i = 0; i < number_of_intervals; i++) {
                        evaluation_point += 4.0 * step_size;
                        integral_value += 32.0 * (f(evaluation_point) + f(evaluation_point + 2 * step_size));
                    }
                    evaluation_point = interval[0] - 2.0 * step_size;
                    for (i = 0; i < number_of_intervals; i++) {
                        evaluation_point += 4.0 * step_size;
                        integral_value += 12.0 * f(evaluation_point);
                    }
                    integral_value *= 2.0 * step_size / 45.0;
            }
            return integral_value;
        },

        /**
         * Integral of function f over interval.
         * @param {Array} interval The integration interval, e.g. [0, 3].
         * @param {function} f A function which takes one argument of type number and returns a number.
         * @returns {Number} The value of the integral of f over interval
         * @see JXG.Math.Numerics.NewtonCotes
         */
        I: function(interval, f) {
            return this.NewtonCotes(interval, f, {number_of_nodes: 16, integration_type: 'milne'});
        },

        /**
         * Newton's method to find roots of a funtion in one variable.
         * @param {function} f We search for a solution of f(x)=0.
         * @param {Number} x initial guess for the root, i.e. start value.
         * @param {object} object optional object that is treated as "this" in the function body. This is useful, if the function is a
         *                 method of an object and contains a reference to its parent object via "this".
         * @returns {Number} A root of the function f.
         */
        Newton: function(f, x, object) {
            var i = 0,
                h = JXG.Math.eps,
                newf = f.apply(object, [x]), // set "this" to "object" in f
                nfev = 1, 
                df;
            if (JXG.isArray(x)) {  // For compatibility
                x = x[0];
            }
            while (i < 50 && Math.abs(newf) > h) {
                df = this.D(f, object)(x);  nfev += 2;
                if (Math.abs(df) > h) {
                    x -= newf / df;
                } else {
                    x += (Math.random() * 0.2 - 1.0);
                }
                newf = f.apply(object, [x]); nfev++;
                i++;
            }
            //JXG.debug("N nfev="+nfev);
            return x;
        },

        /**
         * Abstract method to find roots of univariate functions.
         * @param {function} f We search for a solution of f(x)=0.
         * @param {Number} x initial guess for the root, i.e. staring value.
         * @param {object} object optional object that is treated as "this" in the function body. This is useful, if the function is a
         *                 method of an object and contains a reference to its parent object via "this".
         * @returns {Number} A root of the function f.
         */
        root: function(f, x, object) {
            //return this.Newton(f, x, object);
            return this.fzero(f, x, object);
        },

        /**
         * Returns the Lagrange polynomials for curves with equidistant nodes, see
         * Jean-Paul Berrut, Lloyd N. Trefethen: Barycentric Lagrange Interpolation,
         * SIAM Review, Vol 46, No 3, (2004) 501-517.
         * The graph of the parametric curve [x(t),y(t)] runs through the given points.
         * @param {Array} p Array of JXG.Points
         * @returns {Array} An array consisting of two functions x(t), y(t) which define a parametric curve
         * f(t) = (x(t), y(t)) and two numbers x1 and x2 defining the curve's domain. x1 always equals zero.
         */
        Neville: function(p) {
            var w = [],
                makeFct = function(fun) {
                    return function(t, suspendedUpdate) {
                        var i, d, s,
                            bin = JXG.Math.binomial,
                            len = p.length,
                            len1 = len - 1,
                            num = 0.0,
                            denom = 0.0;

                        if (!suspendedUpdate) {
                            s = 1;
                            for (i = 0; i < len; i++) {
                                w[i] = bin(len1, i) * s;
                                s *= (-1);
                            }
                        }

                        d = t;
                        for (i = 0; i < len; i++) {
                            if (d === 0) {
                                return p[i][fun]();
                            } else {
                                s = w[i] / d;
                                d--;
                                num += p[i][fun]() * s;
                                denom += s;
                            }
                        }
                        return num / denom;
                    };
                },

                xfct = makeFct('X'),
                yfct = makeFct('Y');

            return [xfct, yfct, 0, function() {
                return p.length - 1;
            }];
        },

        /**
         * Calculates second derivatives at the given knots.
         * @param {Array} x x values of knots
         * @param {Array} y y values of knots
         * @returns {Array} Second derivatives of the interpolated function at the knots.
         * @see #splineEval
         */
        splineDef: function(x, y) {
            var n = Math.min(x.length, y.length),
                pair, i, l,
                diag = [],
                z = [],
                data = [],
                dx = [],
                delta = [],
                F = [];

            if (n === 2) {
                return [0, 0];
            }

            for (i = 0; i < n; i++) {
                pair = {X: x[i], Y: y[i]};
                data.push(pair);
            }
            data.sort(function (a, b) {
                return a.X - b.X;
            });
            for (i = 0; i < n; i++) {
                x[i] = data[i].X;
                y[i] = data[i].Y;
            }

            for (i = 0; i < n - 1; i++) {
                dx.push(x[i + 1] - x[i]);
            }
            for (i = 0; i < n - 2; i++) {
                delta.push(6 * (y[i + 2] - y[i + 1]) / (dx[i + 1]) - 6 * (y[i + 1] - y[i]) / (dx[i]));
            }

            // ForwardSolve
            diag.push(2 * (dx[0] + dx[1]));
            z.push(delta[0]);

            for (i = 0; i < n - 3; i++) {
                l = dx[i + 1] / diag[i];
                diag.push(2 * (dx[i + 1] + dx[i + 2]) - l * dx[i + 1]);
                z.push(delta[i + 1] - l * z[i]);
            }

            // BackwardSolve
            F[n - 3] = z[n - 3] / diag[n - 3];
            for (i = n - 4; i >= 0; i--) {
                F[i] = (z[i] - (dx[i + 1] * F[i + 1])) / diag[i];
            }

            // Generate f''-Vector
            for (i = n - 3; i >= 0; i--) {
                F[i + 1] = F[i];
            }

            // natural cubic spline
            F[0] = 0;
            F[n - 1] = 0;
            return F;
        },

        /**
         * Evaluate points on spline.
         * @param {Number,Array} x0 A single float value or an array of values to evaluate
         * @param {Array} x x values of knots
         * @param {Array} y y values of knots
         * @param {Array} F Second derivatives at knots, calculated by {@link #splineDef}
         * @see #splineDef
         * @returns {Number,Array} A single value or an array, depending on what is given as x0.
         */
        splineEval: function(x0, x, y, F) {
            var n = Math.min(x.length, y.length),
                l = 1,
                asArray = false,
                y0 = [],
                i, j, a, b, c, d, x_;

            // number of points to be evaluated
            if (JXG.isArray(x0)) {
                l = x0.length;
                asArray = true;
            } else
                x0 = [x0];

            for (i = 0; i < l; i++) {
                // is x0 in defining interval?
                if ((x0[i] < x[0]) || (x[i] > x[n - 1]))
                    return NaN;

                // determine part of spline in which x0 lies
                for (j = 1; j < n; j++) {
                    if (x0[i] <= x[j])
                        break;
                }
                j--;

                // we're now in the j-th partial interval, i.e. x[j] < x0[i] <= x[j+1];
                // determine the coefficients of the polynomial in this interval
                a = y[j];
                b = (y[j + 1] - y[j]) / (x[j + 1] - x[j]) - (x[j + 1] - x[j]) / 6 * (F[j + 1] + 2 * F[j]);
                c = F[j] / 2;
                d = (F[j + 1] - F[j]) / (6 * (x[j + 1] - x[j]));
                // evaluate x0[i]
                x_ = x0[i] - x[j];
                //y0.push(a + b*x_ + c*x_*x_ + d*x_*x_*x_);
                y0.push(a + (b + (c + d * x_) * x_) * x_);
            }

            if (asArray)
                return y0;
            else
                return y0[0];
        },

        /**
         * Generate a string containing the function term of a polynomial.
         * @param {Array} coeffs Coefficients of the polynomial. The position i belongs to x^i.
         * @param {Number} deg Degree of the polynomial
         * @param {String} varname Name of the variable (usually 'x')
         * @param {Number} prec Precision
         * @returns {String} A string containg the function term of the polynomial.
         */
        generatePolynomialTerm: function(coeffs, deg, varname, prec) {
            var t = [], i;
            for (i = deg; i >= 0; i--) {
                t = t.concat(['(', coeffs[i].toPrecision(prec), ')']);
                if (i > 1) {
                    t = t.concat(['*', varname, '<sup>', i, '<', '/sup> + ']);
                } else if (i === 1) {
                    t = t.concat(['*', varname, ' + ']);
                }
            }
            return t.join('');
        },

        /**
         * Computes the polynomial through a given set of coordinates in Lagrange form.
         * Returns the Lagrange polynomials, see
         * Jean-Paul Berrut, Lloyd N. Trefethen: Barycentric Lagrange Interpolation,
         * SIAM Review, Vol 46, No 3, (2004) 501-517.
         * @param {Array} p Array of JXG.Points
         * @returns {function} A function of one parameter which returns the value of the polynomial, whose graph runs through the given points.
         */
        lagrangePolynomial: function(p) {
            var w = [],
                fct = function(x, suspendedUpdate) {
                    var i, k, len, xi, s,
                        num = 0, denom = 0,
                        M, j;

                    len = p.length;
                    if (!suspendedUpdate) {
                        for (i = 0; i < len; i++) {
                            w[i] = 1.0;
                            xi = p[i].X();
                            for (k = 0; k < len; k++) if (k != i) {
                                w[i] *= (xi - p[k].X());
                            }
                            w[i] = 1 / w[i];
                        }

                        M = [];
                        for (j = 0; j < len; j++) {
                            M.push([1]);
                        }
                    }

                    for (i = 0; i < len; i++) {
                        xi = p[i].X();
                        if (x === xi) {
                            return p[i].Y();
                        } else {
                            s = w[i] / (x - xi);
                            denom += s;
                            num += s * p[i].Y();
                        }
                    }
                    return num / denom;
                };

            fct.getTerm = function() {
                return '';
            };

            return fct;
        },
        
        /**
         * Computes the cubic Catmull-Rom spline curve through a given set of points. The curve
         * is uniformly parametrized.
         * Two artificial control points at the beginning and the end are added.
         * @param {Array} points Array consisting of JXG.Points.
         * @returns {Array} An Array consisting of four components: Two functions each of one parameter t
         * which return the x resp. y coordinates of the Catmull-Rom-spline curve in t, a zero value, and a function simply
         * returning the length of the points array minus three.
        */
        CatmullRomSpline: function(points) {
            var coeffs = [],
                p, first = {}, last = {}, // control point at the beginning and at the end
                
                makeFct = function(which) {
                    return function(t, suspendedUpdate) {
                        var len = points.length,
                            s, c;

                        if (len < 2 ) { return NaN; }
                        if (!suspendedUpdate) {
                            first[which] = function() {return 2*points[0][which]()-points[1][which]();}
                            last[which] = function() {return 2*points[len-1][which]()-points[len-2][which]();}
                            p = [first].concat(points, [last]);
                            coeffs[which] = [];
                            for (s=0; s < len-1; s++) {
                                coeffs[which][s] = [
                                    2*p[s+1][which](),
                                     -p[s][which]() +   p[s+2][which](),
                                    2*p[s][which]() - 5*p[s+1][which]() + 4*p[s+2][which]() - p[s+3][which](),
                                     -p[s][which]() + 3*p[s+1][which]() - 3*p[s+2][which]() + p[s+3][which]()
                                    ];
                            }
                        }
                        len += 2;  // add the two control points 
                        if (isNaN(t)) { return NaN; }
                        // This is necessay for our advanced plotting algorithm:
                        if (t < 0) {   
                            return p[1][which]();
                        } else if (t >= len - 3) {
                            return p[len-2][which]();
                        }

                        s = Math.floor(t);
                        if (s==t) {
                            return p[s][which]();
                        }
                        t -= s;
                        c = coeffs[which][s];
                        return 0.5*(((c[3]*t + c[2])*t + c[1])*t + c[0]);
                    };
                };

            return [makeFct('X'),
                makeFct('Y'),
                0,
                function() {
                    return points.length - 1;
                }
            ];
        },

        
        /**
         * Computes the regression polynomial of a given degree through a given set of coordinates.
         * Returns the regression polynomial function.
         * @param {Number} degree number, function or slider.
         * Either
         * @param {Array} dataX array containing the x-coordinates of the data set
         * @param {Array} dataY array containing the y-coordinates of the data set,
         * or
         * @param {Array} dataX Array consisting of JXG.Points.
         * @param {} dataY Ignored
         * @returns {function} A function of one parameter which returns the value of the regression polynomial of the given degree.
         * It possesses the method getTerm() which returns the string containing the function term of the polynomial.
         */
        regressionPolynomial: function(degree, dataX, dataY) {
            var coeffs,
                deg, dX, dY,
                inputType,
                fct,
                term = '';

            if (JXG.isPoint(degree) && typeof degree.Value == 'function') {  // Slider
                deg = function() {return degree.Value();};
            } else if (JXG.isFunction(degree)) {
                deg = degree;
            } else if (JXG.isNumber(degree)) {
                deg = function() {return degree;};
            } else {
                throw new Error("JSXGraph: Can't create regressionPolynomial from degree of type'" + (typeof degree) + "'.");
            }

            if (arguments.length == 3 && JXG.isArray(dataX) && JXG.isArray(dataY)) {              // Parameters degree, dataX, dataY
                inputType = 0;
            } else if (arguments.length == 2 && JXG.isArray(dataX) && dataX.length > 0 && JXG.isPoint(dataX[0])) {  // Parameters degree, point array
                inputType = 1;
            } else {
                throw new Error("JSXGraph: Can't create regressionPolynomial. Wrong parameters.");
            }

            fct = function(x, suspendedUpdate) {
                var i, j, M, MT, y, B, c, s,
                    d, len = dataX.length;                        // input data

                d = Math.floor(deg());                      // input data
                if (!suspendedUpdate) {
                    if (inputType === 1) {  // point list as input
                        dX = [];
                        dY = [];
                        for (i = 0; i < len; i++) {
                            dX[i] = dataX[i].X();
                            dY[i] = dataX[i].Y();
                        }
                    }

                    if (inputType === 0) {  // check for functions
                        dX = [];
                        dY = [];
                        for (i = 0; i < len; i++) {
                            if (JXG.isFunction(dataX[i]))
                                dX.push(dataX[i]());
                            else
                                dX.push(dataX[i]);
                            if (JXG.isFunction(dataY[i]))
                                dY.push(dataY[i]());
                            else
                                dY.push(dataY[i]);
                        }
                    }

                    M = [];
                    for (j = 0; j < len; j++) {
                        M.push([1]);
                    }
                    for (i = 1; i <= d; i++) {
                        for (j = 0; j < len; j++) {
                            M[j][i] = M[j][i - 1] * dX[j];      // input data
                        }
                    }

                    y = dY;                                 // input data
                    MT = JXG.Math.transpose(M);
                    B = JXG.Math.matMatMult(MT, M);
                    c = JXG.Math.matVecMult(MT, y);
                    coeffs = JXG.Math.Numerics.Gauss(B, c);
                    term = JXG.Math.Numerics.generatePolynomialTerm(coeffs, d, 'x', 3);
                }

                // Horner's scheme to evaluate polynomial
                s = coeffs[d];
                for (i = d - 1; i >= 0; i--) {
                    s = (s * x + coeffs[i]);
                }
                return s;
            };

            fct.getTerm = function() {
                return term;
            };

            return fct;
        },

        /**
         * Computes the cubic Bezier curve through a given set of points.
         * @param {Array} points Array consisting of 3*k+1 JXG.Points.
         * The points at position k with k mod 3 = 0 are the data points,
         * points at position k with k mod 3 = 1 or 2 are the control points.
         * @returns {Array} An array consisting of two functions of one parameter t which return the
         * x resp. y coordinates of the Bezier curve in t, one zero value, and a third function accepting
         * no parameters and returning one third of the length of the points. 
         */
        bezier: function(points) {
            var len,
                makeFct = function(which) {
                    return function(t, suspendedUpdate) {
                        var z = Math.floor(t) * 3,
                            t0 = t % 1,
                            t1 = 1 - t0;

                        if (!suspendedUpdate) {
                            len = Math.floor(points.length / 3);
                        }

                        if (t < 0) {
                            return points[0][which]();
                        }
                        if (t >= len) {
                            return points[points.length - 1][which]();
                        }
                        if (isNaN(t)) {
                            return NaN;
                        }
                        return t1 * t1 * (t1 * points[z][which]() + 3 * t0 * points[z + 1][which]()) + (3 * t1 * points[z + 2][which]() + t0 * points[z + 3][which]()) * t0 * t0;
                    };
                };

            return [
                makeFct('X'),
                makeFct('Y'),
                0,
                function() {
                    return Math.floor(points.length / 3);
                }];
        },

        /**
         * Computes the B-spline curve of order k (order = degree+1) through a given set of points.
         * @param {Array} points Array consisting of JXG.Points.
         * @param {Number} order Order of the B-spline curve.
         * @todo closed B-spline curves
         * @returns {Array} An Array consisting of four components: Two functions each of one parameter t
         * which return the x resp. y coordinates of the B-spline curve in t, a zero value, and a function simply
         * returning the length of the points array minus one.
         */
        bspline: function(points, order) {
            var knots, N = [],
                _knotVector = function(n, k) {
                    var j, kn = [];
                    for (j = 0; j < n + k + 1; j++) {
                        if (j < k) {
                            kn[j] = 0.0;
                        } else if (j <= n) {
                            kn[j] = j - k + 1;
                        } else {
                            kn[j] = n - k + 2;
                        }
                    }
                    return kn;
                },

                _evalBasisFuncs = function(t, kn, n, k, s) {
                    var i,j,a,b,den,
                        N = [];

                    if (kn[s] <= t && t < kn[s + 1]) {
                        N[s] = 1;
                    } else {
                        N[s] = 0;
                    }
                    for (i = 2; i <= k; i++) {
                        for (j = s - i + 1; j <= s; j++) {
                            if (j <= s - i + 1 || j < 0) {
                                a = 0.0;
                            } else {
                                a = N[j];
                            }
                            if (j >= s) {
                                b = 0.0;
                            } else {
                                b = N[j + 1];
                            }
                            den = kn[j + i - 1] - kn[j];
                            if (den == 0) {
                                N[j] = 0;
                            } else {
                                N[j] = (t - kn[j]) / den * a;
                            }
                            den = kn[j + i] - kn[j + 1];
                            if (den != 0) {
                                N[j] += (kn[j + i] - t) / den * b;
                            }
                        }
                    }
                    return N;
                },
                makeFct = function(which) {
                    return function(t, suspendedUpdate) {
                        var len = points.length,
                            y, j, s,
                            n = len - 1,
                            k = order;

                        if (n <= 0) return NaN;
                        if (n + 2 <= k) k = n + 1;
                        if (t <= 0) return points[0][which]();
                        if (t >= n - k + 2) return points[n][which]();

                        knots = _knotVector(n, k);
                        s = Math.floor(t) + k - 1;
                        N = _evalBasisFuncs(t, knots, n, k, s);

                        y = 0.0;
                        for (j = s - k + 1; j <= s; j++) {
                            if (j < len && j >= 0) y += points[j][which]() * N[j];
                        }
                        return y;
                    };
                };

            return [makeFct('X'),
                makeFct('Y'),
                0,
                function() {
                    return points.length - 1;
                }
            ];
        },

        /**
         * Numerical (symmetric) approximation of derivative. suspendUpdate is piped through, see {@link JXG.Curve#updateCurve}
         * and {@link JXG.Curve#hasPoint}.
         * @param {function} f Function in one variable to be differentiated.
         * @param {object} [obj] Optional object that is treated as "this" in the function body. This is useful, if the function is a
         * method of an object and contains a reference to its parent object via "this".
         * @returns {function} Derivative function of a given function f.
         */
        D: function(f, obj) {
            var h = 0.00001,
                h2 = 1.0 / (h * 2.0);

            if (arguments.length == 1 || (arguments.length > 1 && !JXG.exists(arguments[1]))) {
                return function(x, suspendUpdate) {
                    return (f(x + h, suspendUpdate) - f(x - h, suspendUpdate)) * h2;
                };
            } else { // set "this" to "obj" in f
                return function(x, suspendUpdate) {
                    return (f.apply(obj, [x + h,suspendUpdate]) - f.apply(obj, [x - h,suspendUpdate])) * h2;
                };
            }
        },

        /**
         * Helper function to create curve which displays Riemann sums.
         * Compute coordinates for the rectangles showing the Riemann sum.
         * @param {function} f Function, whose integral is approximated by the Riemann sum.
         * @param {Number} n number of rectangles.
         * @param {String} type Type of approximation. Possible values are: 'left', 'right', 'middle', 'lower', 'upper', 'random', or 'trapezodial'.
         * @param {Number} start Left border of the approximation interval
         * @param {Number} end Right border of the approximation interval
         * @returns {Array} An array of two arrays containing the x and y coordinates for the rectangles showing the Riemann sum. This
         * array may be used as parent array of a {@link JXG.Curve}. The third parameteris the riemann sum, i.e. the sum of the volumes of all
         * rectangles.
         */
        riemann: function(f, n, type, start, end) {
            var xarr = [],
                yarr = [],
                i, j = 0,
                delta,
                x = start, y,
                x1, y1, delta1, 
                sum = 0;

            n = Math.round(n);

            xarr[j] = x;
            yarr[j] = 0.0;

            if (n > 0) {
                delta = (end - start) / n;
                delta1 = delta * 0.01; // for 'lower' and 'upper'

                for (i = 0; i < n; i++) {
                    if (type === 'right') {
                        y = f(x + delta);
                    } else if (type === 'middle') {
                        y = f(x + delta * 0.5);
                    } else if ((type === 'left') || (type === 'trapezodial')) {
                        y = f(x);
                    } else if (type === 'lower') {
                        y = f(x);
                        for (x1 = x + delta1; x1 <= x + delta; x1 += delta1) {
                            y1 = f(x1);
                            if (y1 < y) {
                                y = y1;
                            }
                        }
                    } else if (type === 'upper') {
                        y = f(x);
                        for (x1 = x + delta1; x1 <= x + delta; x1 += delta1) {
                            y1 = f(x1);
                            if (y1 > y) {
                                y = y1;
                            }
                        }
                    } else {  // if (type === 'random')
                        y = f(x + delta * Math.random());
                    }

                    j++;
                    xarr[j] = x;
                    yarr[j] = y;
                    j++;
                    x += delta;
                    if (type === 'trapezodial') {
                        y = f(x);
                    }
                    xarr[j] = x;
                    yarr[j] = y;
                    j++;
                    xarr[j] = x;
                    yarr[j] = 0.0;
                    sum += y*delta;
                }
            }
            return [xarr,yarr,sum];
        },

        /**
         * Approximate the integral by Riemann sums.
         * Compute the area described by the riemann sum rectangles.
         * @deprecated Replaced by JXG.Curve.Value(), @see JXG.Curve#riemannsum
         * @param {function} f Function, whose integral is approximated by the Riemann sum.
         * @param {Number} n number of rectangles.
         * @param {String} type Type of approximation. Possible values are: 'left', 'right', 'middle', 'lower', 'upper', 'random'. or 'trapezodial'.
         * @param {Number} start Left border of the approximation interval
         * @param {Number} end Right border of the approximation interval
         * @returns {Number} The sum of the areas of the rectangles.
         */
        riemannsum: function(f, n, type, start, end) {
            var sum = .0,
                i, delta,
                x = start, y,
                x1, y1, delta1;

            n = Math.floor(n);
            if (n > 0) {
                delta = (end - start) / n;
                delta1 = delta * 0.01; // for 'lower' and 'upper'
                for (i = 0; i < n; i++) {
                    if (type === 'right') {
                        y = f(x + delta);
                    } else if (type === 'middle') {
                        y = f(x + delta * 0.5);
                    } else if (type === 'trapezodial') {
                        y = 0.5 * (f(x + delta) + f(x));
                    } else if (type === 'left') {
                        y = f(x);
                    } else if (type === 'lower') {
                        y = f(x);
                        for (x1 = x + delta1; x1 <= x + delta; x1 += delta1) {
                            y1 = f(x1);
                            if (y1 < y) {
                                y = y1;
                            }
                        }
                    } else if (type === 'upper') {
                        y = f(x);
                        for (x1 = x + delta1; x1 <= x + delta; x1 += delta1) {
                            y1 = f(x1);
                            if (y1 > y) {
                                y = y1;
                            }
                        }
                    } else {  // if (type === 'random')
                        y = f(x + delta * Math.random());
                    }
                    sum += delta * y;
                    x += delta;
                }
            }
            return sum;
        },

        /**
         * Solve initial value problems numerically using Runge-Kutta-methods.
         * See {@link http://en.wikipedia.org/wiki/Runge-Kutta_methods} for more information on the algorithm.
         * @param {object,String} butcher Butcher tableau describing the Runge-Kutta method to use. This can be either a string describing
         * a Runge-Kutta method with a Butcher tableau predefined in JSXGraph like 'euler', 'heun', 'rk4' or an object providing the structure
         * <pre>
         * {
         *     s: &lt;Number&gt;,
         *     A: &lt;matrix&gt;,
         *     b: &lt;Array&gt;,
         *     c: &lt;Array&gt;
         * }
         * </pre>
         * which corresponds to the Butcher tableau structure shown here: http://en.wikipedia.org/w/index.php?title=List_of_Runge%E2%80%93Kutta_methods&oldid=357796696
         * @param {Array} x0 Initial value vector. If the problem is of one-dimensional, the initial value also has to be given in an array.
         * @param {Array} I Interval on which to integrate.
         * @param {Number} N Number of evaluation points.
         * @param {function} f Function describing the right hand side of the first order ordinary differential equation, i.e. if the ode
         * is given by the equation <pre>dx/dt = f(t, x(t)).</pre> So f has to take two parameters, a number <tt>t</tt> and a
         * vector <tt>x</tt>, and has to return a vector of the same dimension as <tt>x</tt> has.
         * @returns {Array} An array of vectors describing the solution of the ode on the given interval I.
         * @example
         * // A very simple autonomous system dx(t)/dt = x(t);
         * function f(t, x) {
         *     return x;
         * }
         *
         * // Solve it with initial value x(0) = 1 on the interval [0, 2]
         * // with 20 evaluation points.
         * var data = JXG.Math.Numerics.rungeKutta('heun', [1], [0, 2], 20, f);
         *
         * // Prepare data for plotting the solution of the ode using a curve.
         * var dataX = [];
         * var dataY = [];
         * var h = 0.1;        // (I[1] - I[0])/N  = (2-0)/20
         * for(var i=0; i&lt;data.length; i++) {
         *     dataX[i] = i*h;
         *     dataY[i] = data[i][0];
         * }
         * var g = board.create('curve', [dataX, dataY], {strokeWidth:'2px'});
         * </pre><div id="d2432d04-4ef7-4159-a90b-a2eb8d38c4f6" style="width: 300px; height: 300px;"></div>
         * <script type="text/javascript">
         * var board = JXG.JSXGraph.initBoard('d2432d04-4ef7-4159-a90b-a2eb8d38c4f6', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
         * function f(t, x) {
         *     // we have to copy the value.
         *     // return x; would just return the reference.
         *     return [x[0]];
         * }
         * var data = JXG.Math.Numerics.rungeKutta('heun', [1], [0, 2], 20, f);
         * var dataX = [];
         * var dataY = [];
         * var h = 0.1;
         * for(var i=0; i<data.length; i++) {
         *     dataX[i] = i*h;
         *     dataY[i] = data[i][0];
         * }
         * var g = board.create('curve', [dataX, dataY], {strokeColor:'red', strokeWidth:'2px'});
         * </script><pre>
         */
        rungeKutta: function(butcher, x0, I, N, f) {
            var x = [],
                y = [],
                h = (I[1] - I[0]) / N,
                t = I[0],
                e, i, j,
                k, l,
                dim = x0.length,
                s,
                result = [],
                r = 0;

            if (JXG.isString(butcher)) {
                butcher = predefinedButcher[butcher] || predefinedButcher.euler;
            }
            s = butcher.s;

            // don't change x0, so copy it
            for (e = 0; e < dim; e++)
                x[e] = x0[e];

            for (i = 0; i < N; i++) {
                // Optimization doesn't work for ODEs plotted using time
                //        if((i % quotient == 0) || (i == N-1)) {
                result[r] = [];
                for (e = 0; e < dim; e++)
                    result[r][e] = x[e];
                r++;
                //        }
                // init k
                k = [];
                for (j = 0; j < s; j++) {
                    // init y = 0
                    for (e = 0; e < dim; e++)
                        y[e] = 0.;

                    // Calculate linear combination of former k's and save it in y
                    for (l = 0; l < j; l++) {
                        for (e = 0; e < dim; e++) {
                            y[e] += (butcher.A[j][l]) * h * k[l][e];
                        }
                    }

                    // add x(t) to y
                    for (e = 0; e < dim; e++) {
                        y[e] += x[e];
                    }

                    // calculate new k and add it to the k matrix
                    k.push(f(t + butcher.c[j] * h, y));
                }

                // init y = 0
                for (e = 0; e < dim; e++)
                    y[e] = 0.;

                for (l = 0; l < s; l++) {
                    for (e = 0; e < dim; e++)
                        y[e] += butcher.b[l] * k[l][e];
                }

                for (e = 0; e < dim; e++) {
                    x[e] = x[e] + h * y[e];
                }

                t += h;
            }

            return result;
        },


        /*
         * Maximum number of iterations in @see #fzero
         */
        maxIterationsRoot: 80, 

        /*
         * Maximum number of iterations in @see #fminbr
         */
        maxIterationsMinimize: 500, 
        
        /**
         *
         * Find zero of an univariate function f.
         * @param {function} f Function, whose root is to be found
         * @param {array or number} x0  Start value or start interval enclosing the root
         * @param {object} object Parent object in case f is method of it
         * @return {number} the approximation of the root
         * Algorithm:
         *  G.Forsythe, M.Malcolm, C.Moler, Computer methods for mathematical
         *  computations. M., Mir, 1980, p.180 of the Russian edition
         * 
         * if x0 is an array containing lower and upper bound for the zero
         * algorithm 748 is applied. Otherwise, if x0 is a number,
         * the algorithm tries to bracket a zero of f starting from x0.
         * If this fails, we fall back to Newton's method.
         *
         **/
        fzero: function(f, x0, object) {
            var tol = JXG.Math.eps,
                maxiter = this.maxIterationsRoot, niter = 0,
                nfev = 0,
                eps = tol,
                a,b,c, 
                fa, fb, fc,
                aa, blist, i, len, u, fu, 
                prev_step,
                tol_act,         // Actual tolerance
                p,               // Interpolation step is calcu-
                q,               // lated in the form p/q; divi- 
                                 // sion operations is delayed  
                                 // until the last moment   
                new_step,        // Step at this iteration
                t1, cb, t2;

            if (JXG.isArray(x0)) {
                if (x0.length<2) 
                    throw new Error("JXG.Math.Numerics.fzero: length of array x0 has to be at least two.");
                a = x0[0]; fa = f.apply(object,[a]); nfev++;
                b = x0[1]; fb = f.apply(object,[b]); nfev++;
            } else {
                a = x0; fa = f.apply(object,[a]); nfev++;
                // Try to get b.
                if (a == 0) {
                    aa = 1;
                } else {
                    aa = a;
                }
                blist = [0.9*aa, 1.1*aa, aa-1, aa+1, 0.5*aa, 1.5*aa, -aa, 2*aa, -10*aa, 10*aa];
                len = blist.length;
                for (i=0;i<len;i++) {
                    b = blist[i];
                    fb = f.apply(object,[b]); nfev++;
                    if (fa*fb<=0) {
                        break;
                    }
                }
                if (b < a) {
                    u = a; a = b; b = u;
                    fu = fa; fa = fb; fb = fu;
                }
            }

            if (fa*fb > 0) {
                // Bracketing not successful, fall back to Newton's method or to fminbr
                if (JXG.isArray(x0)) {
                    //JXG.debug("fzero falls back to fminbr");
                    return this.fminbr(f, [a,b], object);
                } else {
                    //JXG.debug("fzero falls back to Newton");
                    return this.Newton(f, a, object);
                }
            }

            // OK, we have enclosed a zero of f.
            // Now we can start Brent's method

            c = a;   
            fc = fa;
            while (niter<maxiter) {   // Main iteration loop
                prev_step = b-a;      // Distance from the last but one
                                      // to the last approximation 

                if ( Math.abs(fc) < Math.abs(fb) ) {
                                                // Swap data for b to be the  
                    a = b;  b = c;  c = a;      // best approximation   
                    fa=fb;  fb=fc;  fc=fa;
                }
                tol_act = 2*eps*Math.abs(b) + tol*0.5;
                new_step = (c-b)*0.5;

                if ( Math.abs(new_step) <= tol_act && Math.abs(fb) <= eps ) {
                    //JXG.debug("nfev="+nfev);
                    return b;                           //  Acceptable approx. is found 
                }
                    
                // Decide if the interpolation can be tried 
                if ( Math.abs(prev_step) >= tol_act     // If prev_step was large enough
                    && Math.abs(fa) > Math.abs(fb) ) {  // and was in true direction,  
                                                        // Interpolatiom may be tried  
                    cb = c-b;
                    if ( a==c ) {                       // If we have only two distinct 
                                                        // points linear interpolation 
                        t1 = fb/fa;                     // can only be applied    
                        p = cb*t1;
                        q = 1.0 - t1;
                    } else {                            // Quadric inverse interpolation
                        q = fa/fc;  t1 = fb/fc;  t2 = fb/fa;
                        p = t2 * ( cb*q*(q-t1) - (b-a)*(t1-1.0) );
                        q = (q-1.0) * (t1-1.0) * (t2-1.0);
                    }
                    if ( p>0 ) {                        // p was calculated with the op-
                        q = -q;                         // posite sign; make p positive 
                    } else {                            // and assign possible minus to
                        p = -p;                         // q 
                    }
                    
                    if( p < (0.75*cb*q-Math.abs(tol_act*q)*0.5)     // If b+p/q falls in [b,c]
                        && p < Math.abs(prev_step*q*0.5) ) {        // and isn't too large 
                        new_step = p/q;                 // it is accepted   
                    }                                   // If p/q is too large then the 
                                                        // bissection procedure can
                                                        // reduce [b,c] range to more
                                                        // extent
                }

                if ( Math.abs(new_step) < tol_act ) {   // Adjust the step to be not less
                    if ( new_step > 0 ) {               // than tolerance
                        new_step = tol_act;
                    } else {
                        new_step = -tol_act;
                    }
                }

                a = b;  fa = fb;                        // Save the previous approx.
                b += new_step;  
                fb = f.apply(object,[b]); nfev++;       // Do step to a new approxim.
                if ( (fb>0 && fc>0) || (fb<0 && fc<0) ) {
                                                        // Adjust c for it to have a sign
                    c = a;  fc = fa;                    // opposite to that of b 
                }
                niter++;
            }                                           // End while
            
            //JXG.debug("fzero: maxiter="+maxiter+" reached.");
            return b;
        },

     
        /**
         *
         * Find minimum of an univariate function f.
         * @param {function} f Function, whose minimum is to be found
         * @param {array} x0  Start interval enclosing the minimum
         * @param {object} object Parent object in case f is method of it
         * @return {number} the approximation of the minimum
         * Algorithm:
         *  G.Forsythe, M.Malcolm, C.Moler, Computer methods for mathematical
         *  computations. M., Mir, 1980, p.180 of the Russian edition
         * x0 
         **/
        fminbr: function(f, x0, object) {              // An estimate to the min location
            var a, b, x, v, w,
                fx, fv, fw,
                r = (3.-Math.sqrt(5.0))*0.5,            // Golden section ratio   
                tol = JXG.Math.eps,
                sqrteps = Math.sqrt(JXG.Math.eps),
                maxiter = this.maxIterationsMinimize, 
                niter = 0,
                range, middle_range, tol_act, new_step,
                p, q, t, ft,
                nfev = 0;

            if (!JXG.isArray(x0) || x0.length<2) {
                throw new Error("JXG.Math.Numerics.fminbr: length of array x0 has to be at least two.");
            }
            a = x0[0];
            b = x0[1];
            v = a + r*(b-a);  
            fv = f.apply(object,[v]); nfev++;           // First step - always gold section
            x = v;  w = v;
            fx=fv;  fw=fv;

            while (niter<maxiter) {
                range = b-a;                            // Range over which the minimum 
                                                        // is seeked for
                middle_range = (a+b)*0.5;
                tol_act = sqrteps*Math.abs(x) + tol/3;  // Actual tolerance  
                if( Math.abs(x-middle_range) + range*0.5 <= 2*tol_act ) {
                    //JXG.debug(nfev);
                    return x;                           // Acceptable approx. is found
                }
                                                        // Obtain the golden section step 
                new_step = r * ( x<middle_range ? b-x : a-x );
                                                        // Decide if the interpolation can be tried 
                if ( Math.abs(x-w) >= tol_act  ) {      // If x and w are distinct     
                                                        // interpolatiom may be tried 
                    // Interpolation step is calculated as p/q; 
                    // division operation is delayed until last moment 
                    t = (x-w) * (fx-fv);
                    q = (x-v) * (fx-fw);
                    p = (x-v)*q - (x-w)*t;
                    q = 2*(q-t);

                    if ( q>0 ) {                        // q was calculated with the op-
                        p = -p;                         // posite sign; make q positive 
                    } else {                            // and assign possible minus to
                        q = -q;                         // p
                    }
                    if ( Math.abs(p) < Math.abs(new_step*q) &&      // If x+p/q falls in [a,b]
                         p > q*(a-x+2*tol_act) &&                   //  not too close to a and
                         p < q*(b-x-2*tol_act)  ) {                 // b, and isn't too large */
                         new_step = p/q;                            // it is accepted        
                    }
                    // If p/q is too large then the 
                    // golden section procedure can   
                    // reduce [a,b] range to more   
                    // extent           
                }

                if ( Math.abs(new_step) < tol_act ) {    // Adjust the step to be not less
                    if( new_step > 0 ) {                 // than tolerance     
                        new_step = tol_act;
                    } else {
                        new_step = -tol_act;
                    }
                }
                
                // Obtain the next approximation to min 
                // and reduce the enveloping range
                t = x + new_step;                       // Tentative point for the min
                ft = f.apply(object,[t]); nfev++;
                if ( ft <= fx ) {                       // t is a better approximation 
                    if ( t < x ) {                      // Reduce the range so that
                        b = x;                          // t would fall within it 
                    } else {
                        a = x;
                    }
                    v = w;  w = x;  x = t;              // Assign the best approx to x 
                    fv=fw;  fw=fx;  fx=ft;
                } else {                                // x remains the better approx
                    if ( t < x ) {                      // Reduce the range enclosing x 
                        a = t;                   
                    } else {
                        b = t;
                    }
                    if ( ft <= fw || w==x ) {
                        v = w;  w = t;
                        fv=fw;  fw=ft;
                    } else if ( ft<=fv || v==x || v==w ) {
                        v = t;
                        fv=ft;
                    }
                }
                niter++;
            } 
            //JXG.debug("fminbr: maxiter="+maxiter+" reached.");
            return x;
        },

        /**
         * Helper function to create curve which displays Reuleaux polygons.
         * @param {array} points Array of points which should be the vertices of the Reuleaux polygon. Typically,
         *                       these point list is the array vrtices of a regular polygon.
         * @param {number} nr Number of vertices
         * @returns {array} An array containing the two functions defining the Reuleaux polygon and the two values
         * for the start and the end of the paramtric curve.
         * array may be used as parent array of a {@link JXG.Curve}.
         *
         * @example
         * var A = brd.create('point',[-2,-2]);
         * var B = brd.create('point',[0,1]);
         * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0}); 
         * var reuleauxTriangle = brd.create('curve', JXG.Math.Numerics.reuleauxPolygon(pol.vertices, 3), 
         *                          {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});
         *
         * </pre><div id="2543a843-46a9-4372-abc1-94d9ad2db7ac" style="width: 300px; height: 300px;"></div>
         * <script type="text/javascript">
         * var brd = JXG.JSXGraph.initBoard('2543a843-46a9-4372-abc1-94d9ad2db7ac', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false});
         * var A = brd.create('point',[-2,-2]);
         * var B = brd.create('point',[0,1]);
         * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0}); 
         * var reuleauxTriangle = brd.create('curve', JXG.Math.Numerics.reuleauxPolygon(pol.vertices, 3), 
         *                          {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});
         * </script><pre>
         */
        reuleauxPolygon: function(points, nr) {
            var pi2 = Math.PI*2,
                pi2_n = pi2/nr,
                diag = (nr-1)/2,
                beta, d = 0,
                makeFct = function(which, trig) {
                    return function(t, suspendUpdate) {
                        if (!suspendUpdate) {
                            d = points[0].Dist(points[diag]);
                            beta = JXG.Math.Geometry.rad([points[0].X()+1,points[0].Y()],points[0],points[(diag)%nr]);
                        }
                        var t1 = (t%pi2 + pi2) % pi2;
                        var j = Math.floor(t1 / pi2_n)%nr;
                        if (isNaN(j)) return j;
                        //t1 = (t1-j*pi2_n)*0.5 + beta+j*pi2_n;
                        t1 = t1*0.5+j*pi2_n*0.5 + beta;
                        return points[j][which]()+d*Math[trig](t1);
                    };
                };
            return [
                makeFct('X','cos'),
                makeFct('Y','sin'),
                0,
                Math.PI*2
            ];
        },

        /**
         * Implements the Ramer-Douglas-Peuker algorithm.
         * It discards points which are not necessary from the polygonal line defined by the point array
         * pts. The computation is done in screen coordinates.
         * Average runtime is O(nlog(n)), worst case runtime is O(n^2), where n is the number of points.
         * @param {Array} pts Array of {@link JXG.Coords}
         * @param {Number} eps If the absolute value of a given number <tt>x</tt> is smaller than <tt>eps</tt> it is considered to be equal <tt>0</tt>.
         * @returns {Array} An array containing points which represent an apparently identical curve as the points of pts do, but contains fewer points.
         */
        RamerDouglasPeuker: function(pts, eps) {
            var newPts = [], i, k, len,
                /**
                 * RDP() is a private subroutine of {@link JXG.Math.Numerics#RamerDouglasPeuker}.
                 * It runs recursively through the point set and searches the
                 * point which has the largest distance from the line between the first point and
                 * the last point. If the distance from the line is greater than eps, this point is
                 * included in our new point set otherwise it is discarded.
                 * If it is taken, we recursively apply the subroutine to the point set before
                 * and after the chosen point.
                 * @param {Array} pts Array of {@link JXG.Coords}
                 * @param {Number} i Index of an element of pts
                 * @param {Number} j Index of an element of pts
                 * @param {Number} eps If the absolute value of a given number <tt>x</tt> is smaller than <tt>eps</tt> it is considered to be equal <tt>0</tt>.
                 * @param {Array} newPts Array of {@link JXG.Coords}
                 * @private
                 */
                RDP = function(pts, i, j, eps, newPts) {
                    var result = findSplit(pts, i, j);

                    if (result[0] > eps) {
                        RDP(pts, i, result[1], eps, newPts);
                        RDP(pts, result[1], j, eps, newPts);
                    } else {
                        newPts.push(pts[j]);
                    }
                },
                /**
                 * findSplit() is a subroutine of {@link JXG.Math.Numerics#RamerDouglasPeuker}.
                 * It searches for the point between index i and j which
                 * has the largest distance from the line between the points i and j.
                 * @param {Array} pts Array of {@link JXG.Coords}
                 * @param {Number} i Index of a point in pts
                 * @param {Number} j Index of a point in pts
                 **/
                findSplit = function(pts, i, j) {
                    var dist = 0,
                        f = i,
                        d, k, ci, cj, ck,
                        x0, y0, x1, y1,
                        den, lbda;

                    if (j - i < 2) return [-1.0,0];

                    ci = pts[i].scrCoords;
                    cj = pts[j].scrCoords;
                    if (isNaN(ci[1] + ci[2] + cj[1] + cj[2])) return [NaN,j];

                    for (k = i + 1; k < j; k++) {
                        ck = pts[k].scrCoords;
                        x0 = ck[1] - ci[1];
                        y0 = ck[2] - ci[2];
                        x1 = cj[1] - ci[1];
                        y1 = cj[2] - ci[2];
                        den = x1 * x1 + y1 * y1;
                        /*
                        if (den >= JXG.Math.eps) {
                            lbda = (x0 * x1 + y0 * y1) / den;
                            d = x0 * x0 + y0 * y0 - lbda * (x0 * x1 + y0 * y1);
                        } else {
                            lbda = 0.0;
                            d = x0 * x0 + y0 * y0;
                        }
                        if (lbda < 0.0) {
                            d = x0 * x0 + y0 * y0;
                        } else if (lbda > 1.0) {
                            x0 = ck[1] - cj[1];
                            y0 = ck[2] - cj[2];
                            d = x0 * x0 + y0 * y0;
                        }
                        */
                        if (den >= JXG.Math.eps) {
                            lbda = (x0 * x1 + y0 * y1) / den;
                            //d = x0 * x0 + y0 * y0 - lbda * (x0 * x1 + y0 * y1);
                            if (lbda<0.0) {
                                lbda = 0.0;
                            } else if (lbda>1.0) {
                                lbda = 1.0;
                            }
                            x0 = x0-lbda*x1;
                            y0 = y0-lbda*y1;
                            d = x0*x0+y0*y0;
                        } else {
                            lbda = 0.0;
                            d = x0 * x0 + y0 * y0;
                        }
                        
                        if (d > dist) {
                            dist = d;
                            f = k;
                        }
                    }
                    return [Math.sqrt(dist),f];
                };

            len = pts.length;

            // Search for the left most point woithout NaN coordinates
            i = 0;
            while (i < len && isNaN(pts[i].scrCoords[1] + pts[i].scrCoords[2])) {
                i++;
            }
            // Search for the right most point woithout NaN coordinates
            k = len - 1;
            while (k > i && isNaN(pts[k].scrCoords[1] + pts[k].scrCoords[2])) {
                k--;
            }

            // Only proceed if something is left
            if (!(i > k || i == len)) {
                newPts[0] = pts[i];
                RDP(pts, i, k, eps, newPts);
            }

            return newPts;
        }

    }
})(JXG, Math);



/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * Functions for mathematical statistics. Most functions are like in the statistics package R.
 * @namespace
 */
JXG.Math.Statistics = {

    /**
     * Sums up all elements of the given array.
     * @param {Array} arr An array of numbers.
     * @returns {Number}
     */
    sum: function (arr) {
        var i, len = arr.length, res = 0;

        for (i = 0; i<len; i++) {
            res += arr[i];
        }
        return res;
    },

    /**
     * Multiplies all elements of the given array.
     * @param {Array} arr An array of numbers.
     * @returns {Number}
     */
    prod: function (arr) {
        var i, len = arr.length, res = 1;

        for (i = 0; i < len; i++) {
            res *= arr[i];
        }
        return res;
    },

    /**
     * Determines the mean value of the values given in an array.
     * @param {Array} arr
     * @returns {Number}
     */
    mean: function (arr) {
        if (arr.length > 0) {
            return this.sum(arr)/arr.length;
        } else {
            return 0.0;
        }
    },

    /**
     * The median of a finite set of values is the value that divides the set
     * into two equal sized subsets.
     * @param {Array} arr The set of values.
     * @returns {Number}
     */
    median: function (arr) {
        var tmp, len;

        if (arr.length > 0) {
            tmp = arr.slice(0);
            tmp.sort(function(a, b) {
                return a - b;
            });
            len = tmp.length;
            if (len % 2 == 1) {
                return tmp[parseInt(len*0.5)];
            } else{
                return (tmp[len*0.5-1]+tmp[len*0.5])*0.5;
            }
        } else {
            return 0.0;
        }
    },

    /**
     * Bias-corrected sample variance. A variance is a measure of how far a
     * set of numbers are spread out from each other.
     * @param {Array} arr
     * @returns {Number}
     */
    variance: function (arr) {
        var m, res, i, len = arr.length;

        if (len > 1) {
            m = this.mean(arr);
            res = 0;
            for(i = 0; i < len; i++) {
                res += (arr[i] - m) * (arr[i] - m);
            }
            return res/(arr.length - 1);
        } else {
            return 0.0;
        }
    },

    /**
     * Determines the <strong>s</strong>tandard <strong>d</strong>eviation which shows how much
     * variation there is from the average value of a set of numbers.
     * @param {Array} arr
     * @returns {Number}
     */
    sd: function (arr) {
        return Math.sqrt(this.variance(arr));
    },

    /**
     * Weighted mean value is basically the same as {@link JXG.Math.Statistics#mean} but here the values
     * are weighted, i.e. multiplied with another value called <em>weight</em>. The weight values are given
     * as a second array with the same length as the value array..
     * @throws {Error} If the dimensions of the arrays don't match.
     * @param {Array} arr Set of alues.
     * @param {Array} w Weight values.
     * @returns {Number}
     */
    weightedMean: function (arr, w) {
        if (arr.length != w.length) {
            throw new Error('JSXGraph error (Math.Statistics.weightedMean): Array dimension mismatch.');
        }

        if (arr.length > 0) {
            return this.mean(this.multiply(arr, w));
        } else {
            return 0.0;
        }
    },

    /**
     * Extracts the maximum value from the array.
     * @param {Array} arr
     * @returns {Number} The highest number from the array. It returns <tt>NaN</tt> if not every element could be
     * interpreted as a number and <tt>-Infinity</tt> if an empty array is given or no element could be interpreted
     * as a number.
     */
    max: function (arr) {
        return Math.max.apply(this, arr);
    },

    /**
     * Extracts the minimum value from the array.
     * @param {Array} arr
     * @returns {Number} The lowest number from the array. It returns <tt>NaN</tt> if not every element could be
     * interpreted as a number and <tt>Infinity</tt> if an empty array is given or no element could be interpreted
     * as a number.
     */
    min: function (arr) {
        return Math.min.apply(this, arr);
    },

    /**
     * Determines the lowest and the highest value from the given array.
     * @param {Array} arr
     * @returns {Array} The minimum value as the first and the maximum value as the second value.
     */
    range: function (arr) {
        return [this.min(arr), this.max(arr)];
    },

    /**
     * Determines the absolute value of every given value.
     * @param {Array|Number} arr
     * @returns {Array|Number}
     */
    abs: function (arr) {
        var i, len, res;

        if (JXG.isArray(arr)) {
            len = arr.length;
            res = [];

            for (i = 0; i < len; i++) {
                res[i] = Math.abs(arr[i]);
            }
        } else {
            res = Math.abs(arr);
        }

        return res;
    },

    /**
     * Adds up two (sequences of) values. If one value is an array and the other one is a number the number
     * is added to every element of the array. If two arrays are given and the lengths don't match the shortest
     * length is taken.
     * @param {Array|Number} arr1
     * @param {Array|Number} arr2
     * @returns {Array|Number}
     */
    add: function (arr1, arr2) {
        var i, len, res = [];

        if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
            len = arr1.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] + arr2;
            }
        } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
            len = arr2.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1 + arr2[i];
            }
        } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
            len = Math.min(arr1.length, arr2.length);

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] + arr2[i];
            }
        } else {
            res = arr1 + arr2;
        }
        
        return res;
    },

    /**
     * Divides two (sequences of) values. If two arrays are given and the lengths don't match the shortest length
     * is taken.
     * @param {Array|Number} arr1 Dividend
     * @param {Array|Number} arr2 Divisor
     * @returns {Array|Number}
     */
    div: function (arr1, arr2) {
        var i, len, res = [];

        if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
            len = arr1.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] / arr2;
            }
        } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
            len = arr2.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1 / arr2[i];
            }
        } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
            len = Math.min(arr1.length, arr2.length);

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] / arr2[i];
            }
        } else {
            res = arr1 / arr2;
        }

        return res;
    },

    /**
     * @function
     * @deprecated Use {@link JXG.Math.Statistics#div} instead.
     */
    divide: JXG.shortcut(JXG.Math.Statistics, 'div'),

    /**
     * Divides two (sequences of) values and returns the remainder. If two arrays are given and the lengths don't
     * match the shortest length is taken.
     * @param {Array|Number} arr1 Dividend
     * @param {Array|Number} arr2 Divisor
     * @param {Boolean} [math=false] Mathematical mod or symmetric mod? Default is symmetric, the JavaScript <tt>%</tt> operator.
     * @returns {Array|Number}
     */
    mod: function (arr1, arr2, math) {
        var i, len, res = [], mod = function (a, m) {
            return a % m;
        };

        math = JXG.def(math, false);

        if (math) {
            mod = JXG.Math.mod;
        }

        if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
            len = arr1.length;

            for (i = 0; i < len; i++) {
                res[i] = mod(arr1[i], arr2);
            }
        } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
            len = arr2.length;

            for (i = 0; i < len; i++) {
                res[i] = mod(arr1, arr2[i]);
            }
        } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
            len = Math.min(arr1.length, arr2.length);

            for (i = 0; i < len; i++) {
                res[i] = mod(arr1[i], arr2[i]);
            }
        } else {
            res = mod(arr1, arr2);
        }

        return res;
    },

    /**
     * Multiplies two (sequences of) values. If one value is an array and the other one is a number the number
     * is multiplied to every element of the array. If two arrays are given and the lengths don't match the shortest
     * length is taken.
     * @param {Array|Number} arr1
     * @param {Array|Number} arr2
     * @returns {Array|Number}
     */
    multiply: function (arr1, arr2) {
        var i, len, res = [];

        if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
            len = arr1.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] * arr2;
            }
        } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
            len = arr2.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1 * arr2[i];
            }
        } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
            len = Math.min(arr1.length, arr2.length);

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] * arr2[i];
            }
        } else {
            res = arr1 * arr2;
        }

        return res;
    },

    /**
     * Subtracts two (sequences of) values. If two arrays are given and the lengths don't match the shortest
     * length is taken.
     * @param {Array|Number} arr1 Minuend
     * @param {Array|Number} arr2 Subtrahend
     * @returns {Array|Number}
     */
    subtract: function (arr1, arr2) {
        var i, len, res = [];

        if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
            len = arr1.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] - arr2;
            }
        } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
            len = arr2.length;

            for (i = 0; i < len; i++) {
                res[i] = arr1 - arr2[i];
            }
        } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
            len = Math.min(arr1.length, arr2.length);

            for (i = 0; i < len; i++) {
                res[i] = arr1[i] - arr2[i];
            }
        } else {
            res = arr1 - arr2;
        }

        return res;
    }
};

/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview In this file the namespace Math.Symbolic is defined, which holds methods
 * and algorithms for symbolic computations.
 * @author graphjs
 */

/**
 * The JXG.Math.Symbolic namespace holds algorithms for symbolic computations.
 * @namespace
 */
JXG.Math.Symbolic = function(JXG, undefined) {

    /** @lends JXG.Math.Symbolic */
    return {
        /**
         * Generates symbolic coordinates for the part of a construction including all the elements from that
         * a specific element depends of. These coordinates will be stored in GeometryElement.symbolic.
         * @param {JXG.Board} board The board that's element get some symbolic coordinates.
         * @param {JXG.GeometryElement} element All ancestor of this element get symbolic coordinates.
         * @param {String} variable Name for the coordinates, e.g. x or u.
         * @param {String} append Method for how to append the number of the coordinates. Possible values are
         *                        'underscore' (e.g. x_2), 'none' (e.g. x2), 'brace' (e.g. x[2]).
         * @returns {Number} Number of coordinates given.
         */
        generateSymbolicCoordinatesPartial: function(board, element, variable, append) {
            var makeCoords = function(num) {
                    var r;
                    if (append === 'underscore')
                        r = '' + variable + '_{' + num + '}';
                    else if (append == 'brace')
                        r = '' + variable + '[' + num + ']';
                    else
                        r = '' + variable + '' + num;

                    return r;
                },
                list = element.ancestors,
                count = 0, t_num, t, k;

            board.listOfFreePoints = [];
            board.listOfDependantPoints = [];

            for (t in list) {
                t_num = 0;
                if (JXG.isPoint(list[t])) {
                    for (k in list[t].ancestors) {
                        t_num++;
                    }
                    if (t_num === 0) {
                        list[t].symbolic.x = list[t].coords.usrCoords[1];
                        list[t].symbolic.y = list[t].coords.usrCoords[2];
                        board.listOfFreePoints.push(list[t]);

                    } else {
                        count++;
                        list[t].symbolic.x = makeCoords(count);
                        count++;
                        list[t].symbolic.y = makeCoords(count);
                        board.listOfDependantPoints.push(list[t]);
                    }

                }
            }

            if (JXG.isPoint(element)) {
                element.symbolic.x = 'x';
                element.symbolic.y = 'y';
            }

            return count;
        },

        /**
         * Clears all .symbolic.x and .symbolic.y members on every point of a given board.
         * @param {JXG.Board} board The board that's points get cleared their symbolic coordinates.
         */
        clearSymbolicCoordinates: function(board) {
            var clear = function(list) {
                    var t, l = (list && list.length) || 0;

                    for (t = 0; t < l; t++) {
                        if (JXG.isPoint(list[t])) {
                            list[t].symbolic.x = '';
                            list[t].symbolic.y = '';
                        }
                    }
                };

            clear(board.listOfFreePoints);
            clear(board.listOfDependantPoints);

            delete (board.listOfFreePoints);
            delete (board.listOfDependantPoints);
        },

        /**
         * Generates polynomials for a part of the construction including all the points from that
         * a specific element depends of.
         * @param {JXG.Board} board The board that's points polynomials will be generated.
         * @param {JXG.GeometryElement} element All points in the set of ancestors of this element are used to generate the set of polynomials.
         * @returns {Array} An array of polynomials as strings.
         */
        generatePolynomials: function(board, element, generateCoords) {
            var list = element.ancestors,
                number_of_ancestors,
                pgs = [],
                result = [],
                t, k, i;

            if (generateCoords)
                this.generateSymbolicCoordinatesPartial(board, element, 'u', 'brace');

            list[element.id] = element;

            for (t in list) {
                number_of_ancestors = 0;
                pgs = [];
                if (JXG.isPoint(list[t])) {
                    for (k in list[t].ancestors) {
                        number_of_ancestors++;
                    }
                    if (number_of_ancestors > 0) {
                        pgs = list[t].generatePolynomial();
                        for (i = 0; i < pgs.length; i++)
                            result.push(pgs[i]);
                    }
                }
            }

            if (generateCoords)
                this.clearSymbolicCoordinates(board);

            return result;
        },

        /**
         * Calculate geometric locus of a point given on a board. Invokes python script on server.
         * @param {JXG.Board} board The board on which the point lies.
         * @param {JXG.Point} point The point that will be traced.
         * @returns {Array} An array of points.
         */
        geometricLocusByGroebnerBase: function(board, point) {
            var numDependent = this.generateSymbolicCoordinatesPartial(board, point, 'u', 'brace'),
                poly, polyStr, result, oldRadius = {},
                xsye = new JXG.Coords(JXG.COORDS_BY_USR, [0,0], board),
                xeys = new JXG.Coords(JXG.COORDS_BY_USR, [board.canvasWidth, board.canvasHeight], board),
                P1, P2, i, sf = 1, transx = 0, transy = 0, rot = 0, c, s, tx,
                xs, xe, ys, ye,

                isIn = function(item, array) {
                    var i;
                    for (i = 0; i < array.length; i++) {
                        if (array[i].id === item) {
                            return true;
                        }
                    }
                    return false;
                },
                bol = board.options.locus;


            if (JXG.Server.modules.geoloci === undefined)
                JXG.Server.loadModule('geoloci');

            if (JXG.Server.modules.geoloci === undefined)
                throw new Error("JSXGraph: Unable to load JXG.Server module 'geoloci.py'.");

            xs = xsye.usrCoords[1];
            xe = xeys.usrCoords[1];
            ys = xeys.usrCoords[2];
            ye = xsye.usrCoords[2];

            // Optimizations - but only if the user wants to
            //   Step 1: Translate all related points, such that one point P1 (board.options.locus.toOrigin if set
            //     or a random point otherwise) is moved to (0, 0)
            //   Step 2: Rotate the construction around the new P1, such that another point P2 (board.options.locus.to10 if set
            //     or a random point \neq P1 otherwise) is moved onto the positive x-axis
            //  Step 3: Dilate the construction, such that P2 is moved to (1, 0)
            //  Step 4: Give the scale factor (sf), the rotation (rot) and the translation vector (transx, transy) to
            //    the server, which retransforms the plot (if any).

            // Step 1
            if (bol.translateToOrigin && (board.listOfFreePoints.length > 0)) {
                if ((bol.toOrigin !== undefined) && (bol.toOrigin != null) && isIn(bol.toOrigin.id, board.listOfFreePoints)) {
                    P1 = bol.toOrigin;
                } else {
                    P1 = board.listOfFreePoints[0];
                }

                transx = P1.symbolic.x;
                transy = P1.symbolic.y;
                // translate the whole construction
                for (i = 0; i < board.listOfFreePoints.length; i++) {
                    board.listOfFreePoints[i].symbolic.x -= transx;
                    board.listOfFreePoints[i].symbolic.y -= transy;
                }

                xs -= transx;
                xe -= transx;
                ys -= transy;
                ye -= transy;

                // Step 2
                if (bol.translateTo10 && (board.listOfFreePoints.length > 1)) {
                    if ((bol.to10 !== undefined) && (bol.to10 != null) && (bol.to10.id != bol.toOrigin.id) && isIn(bol.to10.id, board.listOfFreePoints)) {
                        P2 = bol.to10;
                    } else {
                        if (board.listOfFreePoints[0].id == P1.id)
                            P2 = board.listOfFreePoints[1];
                        else
                            P2 = board.listOfFreePoints[0];
                    }

                    rot = JXG.Math.Geometry.rad([1, 0], [0, 0], [P2.symbolic.x, P2.symbolic.y]);
                    c = Math.cos(-rot);
                    s = Math.sin(-rot);


                    for (i = 0; i < board.listOfFreePoints.length; i++) {
                        tx = board.listOfFreePoints[i].symbolic.x;
                        board.listOfFreePoints[i].symbolic.x = c * board.listOfFreePoints[i].symbolic.x - s * board.listOfFreePoints[i].symbolic.y;
                        board.listOfFreePoints[i].symbolic.y = s * tx + c * board.listOfFreePoints[i].symbolic.y;
                    }

                    // thanks to the rotation this is zero
                    P2.symbolic.y = 0;

                    tx = xs;
                    xs = c * xs - s * ys;
                    ys = s * tx + c * ys;
                    tx = xe;
                    xe = c * xe - s * ye;
                    ye = s * tx + c * ye;

                    // Step 3
                    if (bol.stretch && (Math.abs(P2.symbolic.x) > JXG.Math.eps)) {
                        sf = P2.symbolic.x;

                        for (i = 0; i < board.listOfFreePoints.length; i++) {
                            board.listOfFreePoints[i].symbolic.x /= sf;
                            board.listOfFreePoints[i].symbolic.y /= sf;
                        }

                        for (i in board.objects) {
                            if ((board.objects[i].elementClass == JXG.OBJECT_CLASS_CIRCLE) && (board.objects[i].method == 'pointRadius')) {
                                oldRadius[i] = board.objects[i].radius;
                                board.objects[i].radius /= sf;
                            }
                        }

                        xs /= sf;
                        xe /= sf;
                        ys /= sf;
                        ye /= sf;

                        // this is now 1
                        P2.symbolic.x = 1;
                    }
                }

                // make the coordinates "as rational as possible"
                for (i = 0; i < board.listOfFreePoints.length; i++) {
                    tx = board.listOfFreePoints[i].symbolic.x;
                    if (Math.abs(tx) < JXG.Math.eps)
                        board.listOfFreePoints[i].symbolic.x = 0;
                    if (Math.abs(tx - Math.round(tx)) < JXG.Math.eps)
                        board.listOfFreePoints[i].symbolic.x = Math.round(tx);

                    tx = board.listOfFreePoints[i].symbolic.y;
                    if (Math.abs(tx) < JXG.Math.eps)
                        board.listOfFreePoints[i].symbolic.y = 0;
                    if (Math.abs(tx - Math.round(tx)) < JXG.Math.eps)
                        board.listOfFreePoints[i].symbolic.y = Math.round(tx);
                }
            }

            // end of optimizations

            poly = this.generatePolynomials(board, point);
            polyStr = poly.join(',');

            this.cbp = function(data) {
                //alert(data.exectime);
                //callback(data.datax, data.datay, data.polynomial);
                result = data;
            };

            this.cb = JXG.bind(this.cbp, this);

            JXG.Server.modules.geoloci.lociCoCoA(xs, xe, ys, ye, numDependent, polyStr, sf, rot, transx, transy, this.cb, true);

            this.clearSymbolicCoordinates(board);

            for (i in oldRadius) {
                board.objects[i].radius = oldRadius[i];
            }


            return result;
        }


    }
}(JXG);



/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
*/

/** 
 * @fileoverview This file contains the Math.Geometry namespace for calculating algebraic/geometric
 * stuff like intersection points, angles, midpoint, and so on.
 */


/**
 * Math.Geometry namespace definition
 * @namespace
 */
JXG.Math.Geometry = {};

// the splitting is necessary due to the shortcut for the circumcircleMidpoint method to circumcenter.

JXG.extend(JXG.Math.Geometry, /** @lends JXG.Math.Geometry */ {

    /****************************************/
    /**** GENERAL GEOMETRIC CALCULATIONS ****/
    /****************************************/

    /**
     * Calculates the angle defined by the points A, B, C.
     * @param {JXG.Point} A A point  or [x,y] array.
     * @param {JXG.Point} B Another point or [x,y] array.
     * @param {JXG.Point} C A circle - no, of course the third point or [x,y] array.
     * @deprecated Use {@link JXG.Math.Geometry#rad} instead.
     * @see #rad
     * @see #trueAngle
     * @returns {Number} The angle in radian measure.
     */
    angle: function(A, B, C) {
        var a = [],
            b = [],
            c = [],
            u, v, s, t;

        if (A.coords == null) {
            a[0] = A[0];
            a[1] = A[1];
        } else {
            a[0] = A.coords.usrCoords[1];
            a[1] = A.coords.usrCoords[2];
        }
        if (B.coords == null) {
            b[0] = B[0];
            b[1] = B[1];
        } else {
            b[0] = B.coords.usrCoords[1];
            b[1] = B.coords.usrCoords[2];
        }
        if (C.coords == null) {
            c[0] = C[0];
            c[1] = C[1];
        } else {
            c[0] = C.coords.usrCoords[1];
            c[1] = C.coords.usrCoords[2];
        }
        u = a[0] - b[0];
        v = a[1] - b[1];
        s = c[0] - b[0];
        t = c[1] - b[1];
        return Math.atan2(u * t - v * s, u * s + v * t);
    },

    /**
     * Calculates the angle defined by the three points A, B, C if you're going from A to C around B counterclockwise.
     * @param {JXG.Point} A Point or [x,y] array
     * @param {JXG.Point} B Point or [x,y] array
     * @param {JXG.Point} C Point or [x,y] array
     * @see #rad
     * @returns {Number} The angle in degrees.
     */
    trueAngle: function(A, B, C) {
        return this.rad(A, B, C) * 57.295779513082323; // *180.0/Math.PI;
    },

    /**
     * Calculates the internal angle defined by the three points A, B, C if you're going from A to C around B counterclockwise.
     * @param {JXG.Point} A Point or [x,y] array
     * @param {JXG.Point} B Point or [x,y] array
     * @param {JXG.Point} C Point or [x,y] array
     * @see #trueAngle
     * @returns {Number} Angle in radians.
     */
    rad: function(A, B, C) {
        var ax, ay, bx, by, cx, cy,
            phi;

        if (A.coords == null) {
            ax = A[0];
            ay = A[1];
        } else {
            ax = A.coords.usrCoords[1];
            ay = A.coords.usrCoords[2];
        }
        if (B.coords == null) {
            bx = B[0];
            by = B[1];
        } else {
            bx = B.coords.usrCoords[1];
            by = B.coords.usrCoords[2];
        }
        if (C.coords == null) {
            cx = C[0];
            cy = C[1];
        } else {
            cx = C.coords.usrCoords[1];
            cy = C.coords.usrCoords[2];
        }

        phi = Math.atan2(cy - by, cx - bx) - Math.atan2(ay - by, ax - bx);
        if (phi < 0) phi += 6.2831853071795862;
        return phi;
    },

    /**
     * Calculates the bisection between the three points A, B, C. The bisection is defined by two points:
     * Parameter B and a point with the coordinates calculated in this function.
     * @param {JXG.Point} A Point
     * @param {JXG.Point} B Point
     * @param {JXG.Point} C Point
     * @param [board=A.board] Reference to the board
     * @returns {JXG.Coords} Coordinates of the second point defining the bisection.
     */
    angleBisector: function(A, B, C, board) {
        /* First point */
        var Ac = A.coords.usrCoords,
            Bc = B.coords.usrCoords,
            Cc = C.coords.usrCoords,
            x = Ac[1] - Bc[1],
            y = Ac[2] - Bc[2],
            d = Math.sqrt(x * x + y * y),
            phiA, phiC, phi;

        if (!JXG.exists(board))
            board = A.board;

        x /= d;
        y /= d;

        phiA = Math.acos(x);
        if (y < 0) {
            phiA *= -1;
        }
        if (phiA < 0) {
            phiA += 2 * Math.PI;
        }

        /* Second point */
        x = Cc[1] - Bc[1];
        y = Cc[2] - Bc[2];
        d = Math.sqrt(x * x + y * y);
        x /= d;
        y /= d;

        phiC = Math.acos(x);
        if (y < 0) {
            phiC *= -1;
        }
        if (phiC < 0) {
            phiC += 2 * Math.PI;
        }

        phi = (phiA + phiC) * 0.5;
        if (phiA > phiC) {
            phi += Math.PI;
        }

        x = Math.cos(phi) + Bc[1];
        y = Math.sin(phi) + Bc[2];

        return new JXG.Coords(JXG.COORDS_BY_USER, [x,y], board);
    },

    /**
     * Reflects the point along the line.
     * @param {JXG.Line} line Axis of reflection.
     * @param {JXG.Point} point Point to reflect.
     * @param [board=point.board] Reference to the board
     * @returns {JXG.Coords} Coordinates of the reflected point.
     */
    reflection: function(line, point, board) {
        // (v,w) defines the slope of the line 
        var pc = point.coords.usrCoords,
            p1c = line.point1.coords.usrCoords,
            p2c = line.point2.coords.usrCoords,
            x0, y0, x1, y1, v, w, mu;

        if (!JXG.exists(board))
            board = point.board;

        v = p2c[1] - p1c[1];
        w = p2c[2] - p1c[2];

        x0 = pc[1] - p1c[1];
        y0 = pc[2] - p1c[2];

        mu = (v * y0 - w * x0) / (v * v + w * w);

        // point + mu*(-y,x) waere Lotpunkt 
        x1 = pc[1] + 2 * mu * w;
        y1 = pc[2] - 2 * mu * v;

        return new JXG.Coords(JXG.COORDS_BY_USER, [x1,y1], board);
    },

    /**
     * Computes the new position of a point which is rotated
     * around a second point (called rotpoint) by the angle phi.
     * @param {JXG.Point} rotpoint Center of the rotation
     * @param {JXG.Point} point point to be rotated
     * @param {number} phi rotation angle in arc length
     * @param {JXG.Board} [board=point.board] Reference to the board
     * @returns {JXG.Coords} Coordinates of the new position.
     */
    rotation: function(rotpoint, point, phi, board) {
        var pc = point.coords.usrCoords,
            rotpc = rotpoint.coords.usrCoords,
            x0, y0, c, s, x1, y1;

        if (!JXG.exists(board))
            board = point.board;

        x0 = pc[1] - rotpc[1];
        y0 = pc[2] - rotpc[2];

        c = Math.cos(phi);
        s = Math.sin(phi);

        x1 = x0 * c - y0 * s + rotpc[1];
        y1 = x0 * s + y0 * c + rotpc[2];

        return new JXG.Coords(JXG.COORDS_BY_USER, [x1,y1], board);
    },

    /**
     * Calculates the coordinates of a point on the perpendicular to the given line through
     * the given point.
     * @param {JXG.Line} line A line.
     * @param {JXG.Point} point Intersection point of line to perpendicular.
     * @param {JXG.Board} [board=point.board] Reference to the board
     * @returns {JXG.Coords} Coordinates of a point on the perpendicular to the given line through the given point.
     */
    perpendicular: function(line, point, board) {
        var A = line.point1.coords.usrCoords,
            B = line.point2.coords.usrCoords,
            C = point.coords.usrCoords,
            x, y, change,
            fmd, emc, d0, d1, den;

        if (!JXG.exists(board))
            board = point.board;

        if (point == line.point1) { // Punkt ist erster Punkt der Linie
            x = A[1] + B[2] - A[2];
            y = A[2] - B[1] + A[1];
            change = true;
        } else if (point == line.point2) {  // Punkt ist zweiter Punkt der Linie
            x = B[1] + A[2] - B[2];
            y = B[2] - A[1] + B[1];
            change = false;
        } else if (((Math.abs(A[1] - B[1]) > JXG.Math.eps) &&
            (Math.abs(C[2] - (A[2] - B[2]) * (C[1] - A[1]) / (A[1] - B[1]) - A[2]) < JXG.Math.eps)) ||
            ((Math.abs(A[1] - B[1]) <= JXG.Math.eps) && (Math.abs(A[1] - C[1]) < JXG.Math.eps))) { // Punkt liegt auf der Linie
            x = C[1] + B[2] - C[2];
            y = C[2] - B[1] + C[1];
            change = true;
            if (Math.abs(x - C[1]) < JXG.Math.eps && Math.abs(y - C[2]) < JXG.Math.eps) {
                x = C[1] + A[2] - C[2];
                y = C[2] - A[1] + C[1];
                change = false;
            }
        } else { // Punkt liegt nicht auf der Linie -> als zweiter Punkt wird der Lotfusspunkt gewaehlt
            fmd = A[2] - B[2];
            emc = A[1] - B[1];
            d0 = B[1] * fmd - B[2] * emc;
            d1 = C[1] * emc + C[2] * fmd;
            den = fmd * fmd + emc * emc;
            if (Math.abs(den) < JXG.Math.eps) {
                den = JXG.Math.eps;
            }
            x = (d0 * fmd + d1 * emc) / den;
            y = (d1 * fmd - d0 * emc) / den;
            change = true;
        }
        return [new JXG.Coords(JXG.COORDS_BY_USER, [x, y], board),change];
    },

    /**
     * @deprecated Please use {@link JXG.Math.Geometry#circumcenter} instead.
     */
    circumcenterMidpoint: JXG.shortcut(JXG.Math.Geometry, 'circumcenter'),

    /**
     * Calculates the center of the circumcircle of the three given points.
     * @param {JXG.Point} point1 Point
     * @param {JXG.Point} point2 Point
     * @param {JXG.Point} point3 Point
     * @param {JXG.Board} [board=point1.board] Reference to the board
     * @returns {JXG.Coords} Coordinates of the center of the circumcircle of the given points.
     */
    circumcenter: function(point1, point2, point3, board) {
        var A = point1.coords.usrCoords,
            B = point2.coords.usrCoords,
            C = point3.coords.usrCoords,
            u, v, m1, m2;
            //u, v, den, m1, y, eps = JXG.Math.eps;

        if (!JXG.exists(board))
            board = point1.board;
/*
        u = ((A[1] - B[1]) * (A[1] + B[1]) + (A[2] - B[2]) * (A[2] + B[2])) * 0.5;
        v = ((B[1] - C[1]) * (B[1] + C[1]) + (B[2] - C[2]) * (B[2] + C[2])) * 0.5;
        den = (A[1] - B[1]) * (B[2] - C[2]) - (B[1] - C[1]) * (A[2] - B[2]);

        if (Math.abs(den) < eps) {
            den = eps;
        	return new JXG.Coords(JXG.COORDS_BY_USER, [Infinity, Infinity], board);
        }

        x = (u * (B[2] - C[2]) - v * (A[2] - B[2])) / den;
        y = (v * (A[1] - B[1]) - u * (B[1] - C[1])) / den;

        return new JXG.Coords(JXG.COORDS_BY_USER, [x, y], board);
*/
        u = [B[0]-A[0], -B[2]+A[2], B[1]-A[1]];
        v = [(A[0]+B[0])*0.5, (A[1]+B[1])*0.5, (A[2]+B[2])*0.5];
        m1 = JXG.Math.crossProduct(u, v);
        u = [C[0]-B[0], -C[2]+B[2], C[1]-B[1]];
        v = [(B[0]+C[0])*0.5, (B[1]+C[1])*0.5, (B[2]+C[2])*0.5];
        m2 = JXG.Math.crossProduct(u, v);

        return new JXG.Coords(JXG.COORDS_BY_USER, JXG.Math.crossProduct(m1, m2), board);
    },

    /**
     * Calculates euclidean norm for two given arrays of the same length.
     * @param {Array} array1 Array of float or integer.
     * @param {Array} array2 Array of float or integer.
     * @returns {Number} Euclidean distance of the given vectors.
     */
    distance: function(array1, array2) {
        var sum = 0,
            i, len;

        if (array1.length != array2.length) {
            return NaN;
        }
        len = array1.length;
        for (i = 0; i < len; i++) {
            sum += (array1[i] - array2[i]) * (array1[i] - array2[i]);
        }
        return Math.sqrt(sum);
    },

    /**
     * Calculates euclidean distance for two given arrays of the same length.
     * If one of the arrays contains a zero in the first coordinate, and the euclidean distance
     * is different from zero it is a point at infinity and we return Infinity.
     * @param {Array} array1 Array containing elements of number.
     * @param {Array} array2 Array containing elements of type number.
     * @returns {Number} Euclidean (affine) distance of the given vectors.
     */
    affineDistance: function(array1, array2) {
        var d;
        if (array1.length != array2.length) {
            return NaN;
        }
        d = this.distance(array1, array2);
        if (d > JXG.Math.eps && (Math.abs(array1[0]) < JXG.Math.eps || Math.abs(array2[0]) < JXG.Math.eps)) {
            return Infinity;
        } else {
            return d;
        }
    },

    /**
     * A line can be a segment, a straight, or a ray. so it is not always delimited by point1 and point2
     * calcStraight determines the visual start point and end point of the line. A segment is only drawn
     * from start to end point, a straight line is drawn until it meets the boards boundaries.
     * @param {JXG.Line} el Reference to a line object, that needs calculation of start and end point.
     * @param {JXG.Coords} point1 Coordinates of the point where line drawing begins. This value is calculated and set by this method.
     * @param {JXG.Coords} point2 Coordinates of the point where line drawing ends. This value is calculated and set by this method.
     * @param {Number} margin Optional margin, to avoid the display of the small sides
     * of lines.
     * @see Line
     * @see JXG.Line
     */
    calcStraight: function(el, point1, point2, margin) {
        var takePoint1, takePoint2, intersect1, intersect2, straightFirst, straightLast,
            c, s, i, j, p1, p2;

        if (margin == null) { 
            margin = 10;   // Enlarge the drawable region slightly. This hides the small sides
                           // of thick lines in most cases.
        }
        
        straightFirst = el.visProp.straightfirst;
        straightLast = el.visProp.straightlast;

        // If one of the point is an ideal point in homogeneous coordinates
        // drawing of line segments or rays are not possible.
        if (Math.abs(point1.scrCoords[0]) < JXG.Math.eps) {
            straightFirst = true;
        }
        if (Math.abs(point2.scrCoords[0]) < JXG.Math.eps) {
            straightLast = true;
        }

        if (!straightFirst && !straightLast) {  // Do nothing in case of line segments (inside or outside of the board)
            return;
        }

        // Compute the stdform of the line in screen coordinates.
        c = [];
        c[0] = el.stdform[0] -
                el.stdform[1] * el.board.origin.scrCoords[1] / el.board.unitX +
                el.stdform[2] * el.board.origin.scrCoords[2] / el.board.unitY;
        c[1] = el.stdform[1] / el.board.unitX;
        c[2] = el.stdform[2] / (-el.board.unitY);

        if (isNaN(c[0] + c[1] + c[2])) return; // p1=p2

        // Intersect the line with the four borders of the board.
        s = [];
        s[0] = JXG.Math.crossProduct(c, [margin,0,1]);  // top
        s[1] = JXG.Math.crossProduct(c, [margin,1,0]);  // left
        s[2] = JXG.Math.crossProduct(c, [-margin-el.board.canvasHeight,0,1]);  // bottom
        s[3] = JXG.Math.crossProduct(c, [-margin-el.board.canvasWidth,1,0]);   // right
        
        // Normalize the intersections
        for (i = 0; i < 4; i++) {
            if (Math.abs(s[i][0]) > JXG.Math.eps) {
                for (j = 2; j > 0; j--) {
                    s[i][j] /= s[i][0];
                }
                s[i][0] = 1.0;
            }
        }

        takePoint1 = false;
        takePoint2 = false;
        if (!straightFirst && // Line starts at point1 and point1 is inside the board
                Math.abs(point1.usrCoords[0]) >= JXG.Math.eps &&
                point1.scrCoords[1] >= 0.0 && point1.scrCoords[1] <= el.board.canvasWidth &&
                point1.scrCoords[2] >= 0.0 && point1.scrCoords[2] <= el.board.canvasHeight) {
            takePoint1 = true;
        }
        if (!straightLast && // Line ends at point2 and point2 is inside the board
                Math.abs(point2.usrCoords[0]) >= JXG.Math.eps &&
                point2.scrCoords[1] >= 0.0 && point2.scrCoords[1] <= el.board.canvasWidth &&
                point2.scrCoords[2] >= 0.0 && point2.scrCoords[2] <= el.board.canvasHeight) {
            takePoint2 = true;
        }

        if (Math.abs(s[1][0]) < JXG.Math.eps) {           // line is parallel to "left", take "top" and "bottom"
            intersect1 = s[0];                          // top
            intersect2 = s[2];                          // bottom
        } else if (Math.abs(s[0][0]) < JXG.Math.eps) {           // line is parallel to "top", take "left" and "right"
            intersect1 = s[1];                          // left
            intersect2 = s[3];                          // right
        } else if (s[1][2] < 0) {                         // left intersection out of board (above)
            intersect1 = s[0];                          // top
            if (s[3][2] > el.board.canvasHeight) {        // right intersection out of board (below)
                intersect2 = s[2];                      // bottom
            } else {
                intersect2 = s[3];                      // right
            }
        } else if (s[1][2] > el.board.canvasHeight) {     // left intersection out of board (below)
            intersect1 = s[2];                          // bottom
            if (s[3][2] < 0) {                            // right intersection out of board (above)
                intersect2 = s[0];                      // top
            } else {
                intersect2 = s[3];                      // right
            }
        } else {
            intersect1 = s[1];                          // left
            if (s[3][2] < 0) {                            // right intersection out of board (above)
                intersect2 = s[0];                      // top
            } else if (s[3][2] > el.board.canvasHeight) { // right intersection out of board (below)
                intersect2 = s[2];                      // bottom
            } else {
                intersect2 = s[3];                      // right
            }
        }

        intersect1 = new JXG.Coords(JXG.COORDS_BY_SCREEN, intersect1.slice(1), el.board);
        intersect2 = new JXG.Coords(JXG.COORDS_BY_SCREEN, intersect2.slice(1), el.board);

        /**
         * At this point we have four points:
         * point1 and point2 are the first and the second defining point on the line,
         * intersect1, intersect2 are the intersections of the line with border around the board.
         */
        
        /*
         * Here we handle rays where both defining points are outside of the board.
         */
        if (!takePoint1 && !takePoint2) {              // If both points are outside and the complete ray is outside we do nothing
            if (!straightFirst && straightLast && // Ray starting at point 1
                    !this.isSameDirection(point1, point2, intersect1) && !this.isSameDirection(point1, point2, intersect2)) {
                return;
            } else if (straightFirst && !straightLast && // Ray starting at point 2
                    !this.isSameDirection(point2, point1, intersect1) && !this.isSameDirection(point2, point1, intersect2)) {
                return;
            }
        }

        /*
         * If at least one of the defining points is outside of the board
         * we take intersect1 or intersect2 as one of the end points
         * The order is also important for arrows of axes
         */
        if (!takePoint1) {
            if (!takePoint2) {                                   
                /*
                 * Two border intersection points are used
                 */
                if (this.isSameDir(point1, point2, intersect1, intersect2)) {
                    p1 = intersect1;
                    p2 = intersect2;
                } else {
                    p2 = intersect1;
                    p1 = intersect2;
                }
                    
                /*
                if (this.isSameDirection(point1, point2, intersect1)) {
                    if (!this.isSameDirection(point1, point2, intersect2)) {
                        p2 = intersect1;
                        p1 = intersect2;
                    } else {
                        if (JXG.Math.Geometry.affineDistance(point2.usrCoords, intersect1.usrCoords) <= JXG.Math.Geometry.affineDistance(point2.usrCoords, intersect2.usrCoords)) {
                            p1 = intersect1;
                            p2 = intersect2;
                        } else {
                            p2 = intersect1;
                            p1 = intersect2;
                        }
                    }
                } else {
                    if (this.isSameDirection(point1, point2, intersect2)) {
                        p1 = intersect1;
                        p2 = intersect2;
                    } else {
                        if (JXG.Math.Geometry.affineDistance(point2.usrCoords, intersect1.usrCoords) < JXG.Math.Geometry.affineDistance(point2.usrCoords, intersect2.usrCoords)) {
                            p2 = intersect1;
                            p1 = intersect2;
                        } else {
                            p1 = intersect1;
                            p2 = intersect2;
                        }
                    }
                }
                */
            } else {
                /*
                * One border intersection points is used 
                */
                if (this.isSameDir(point1, point2, intersect1, intersect2)) {
                    p1 = intersect1;
                } else {
                    p1 = intersect2;
                }
                /*
                if (this.isSameDirection(point2, point1, intersect1)) { // Instead of point1 the border intersection is taken
                    p1 = intersect1;
                } else {
                    p1 = intersect2;
                }
                */
            }
        } else {
            if (!takePoint2) {
                /*
                * One border intersection points is used 
                */
                if (this.isSameDir(point1, point2, intersect1, intersect2)) {
                    p2 = intersect2;
                } else {
                    p2 = intersect1;
                } /*
                if (this.isSameDirection(point1, point2, intersect1)) { // Instead of point2 the border intersection is taken
                    p2 = intersect1;
                } else {
                    p2 = intersect2;
                }
                */
            }
        }

        if (p1) point1.setCoordinates(JXG.COORDS_BY_USER, p1.usrCoords.slice(1));
        if (p2) point2.setCoordinates(JXG.COORDS_BY_USER, p2.usrCoords.slice(1));
    },

    /**
     * The vectors p2-p1 and i2-i1 are supposed to be collinear.
     * If their cosine is positive they point into the same direction
     * otherwise they point in opposite direction
     * @param {JXG.Coords} p1 
     * @param {JXG.Coords} p2 
     * @param {JXG.Coords} i1 
     * @param {JXG.Coords} i2 
     * @returns {Boolean} True, if p2-p1 and i2-i1 point into the same direction
     */
    isSameDir: function(p1, p2, i1, i2) {
        var dpx = p2.usrCoords[1] - p1.usrCoords[1],
            dpy = p2.usrCoords[2] - p1.usrCoords[2],
            dix = i2.usrCoords[1] - i1.usrCoords[1],
            diy = i2.usrCoords[2] - i1.usrCoords[2];
            
        if (Math.abs(p2.usrCoords[0])<JXG.Math.eps) {
            dpx = p2.usrCoords[1];
            dpy = p2.usrCoords[2];
        }
        if (Math.abs(p1.usrCoords[0])<JXG.Math.eps) {
            dpx = -p1.usrCoords[1];
            dpy = -p1.usrCoords[2];
        }
            
        return dpx * dix + dpy * diy >= 0;
    },
    
    /**
     * If you're looking from point "start" towards point "s" and can see the point "p", true is returned. Otherwise false.
     * @param {JXG.Coords} start The point you're standing on.
     * @param {JXG.Coords} p The point in which direction you're looking.
     * @param {JXG.Coords} s The point that should be visible.
     * @returns {Boolean} True, if from start the point p is in the same direction as s is, that means s-start = k*(p-start) with k>=0.
     */
    isSameDirection: function(start, p, s) {
        var dx, dy, sx, sy, r = false;

        dx = p.usrCoords[1] - start.usrCoords[1];
        dy = p.usrCoords[2] - start.usrCoords[2];

        sx = s.usrCoords[1] - start.usrCoords[1];
        sy = s.usrCoords[2] - start.usrCoords[2];

        if (Math.abs(dx) < JXG.Math.eps) dx = 0;
        if (Math.abs(dy) < JXG.Math.eps) dy = 0;
        if (Math.abs(sx) < JXG.Math.eps) sx = 0;
        if (Math.abs(sy) < JXG.Math.eps) sy = 0;

        if (dx >= 0 && sx >= 0) {
            if ((dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0)) {
                r = true;
            }
        } else if (dx <= 0 && sx <= 0) {
            if ((dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0)) {
                r = true;
            }
        }

        return r;
    },

    /****************************************/
    /****          INTERSECTIONS         ****/
    /****************************************/

    /**
     * Calculates the coordinates of the intersection of the given lines.
     * @deprecated 
     * @param {JXG.Line} line1 Line.
     * @param {JXG.Line} line2 Line.
     * @param {JXG.Board} [board=line1.board] Reference to the board
     * @returns {JXG.Coords} Coordinates of the intersection point of the given lines.
     */
    intersectLineLine: function(line1, line2, board) {
        var A = line1.point1.coords.usrCoords,
            B = line1.point2.coords.usrCoords,
            C = line2.point1.coords.usrCoords,
            D = line2.point2.coords.usrCoords,
            d0, d1, den, x, y;

        if (!JXG.exists(board))
            board = line1.board;

        d0 = A[1] * B[2] - A[2] * B[1];
        d1 = C[1] * D[2] - C[2] * D[1];
        den = (B[2] - A[2]) * (C[1] - D[1]) - (A[1] - B[1]) * (D[2] - C[2]);

        if (Math.abs(den) < JXG.Math.eps) {
            den = JXG.Math.eps;
        }
        x = (d0 * (C[1] - D[1]) - d1 * (A[1] - B[1])) / den;
        y = (d1 * (B[2] - A[2]) - d0 * (D[2] - C[2])) / den;

        return new JXG.Coords(JXG.COORDS_BY_USER, [x, y], board);
    },

    /**
     * Calculates the coordinates of the intersection of the given line and circle.
     * @deprecated 
     * @param {JXG.Circle} circle Circle.
     * @param {JXG.Line} line Line.
     * @param {JXG.Board} [board=line.board] Reference to the board
     * @returns {Array} The coordinates of the intersection points of the given circle with the given line and
     * the amount of intersection points in the first component of the array.
     */
    intersectCircleLine: function(circle, line, board) {
        var eA = line.point1.coords.usrCoords,
            eB = line.point2.coords.usrCoords,
            fM = circle.center.coords.usrCoords,
            s, d0, d1, b, w, h, r, n1, dx, dy, firstPointX, firstPointY, l, x, y, n1s, firstPoint, secondPoint, d;

        if (!JXG.exists(board))
            board = line.board;

        s = line.point1.Dist(line.point2);
        if (s > 0) {
            d0 = circle.center.Dist(line.point1);
            d1 = circle.center.Dist(line.point2);
            b = ((d0 * d0) + (s * s) - (d1 * d1)) / (2 * s);
            w = (d0 * d0) - (b * b);
            w = (w < 0) ? 0 : w;
            h = Math.sqrt(w);

            r = circle.Radius();
            n1 = Math.sqrt((r * r) - h * h);
            dx = eB[1] - eA[1];
            dy = eB[2] - eA[2];
            firstPointX = fM[1] + (h / s) * dy;
            firstPointY = fM[2] - (h / s) * dx;
            d0 = (eB[1] * dy) - (eB[2] * dx);
            d1 = (firstPointX * dx) + (firstPointY * dy);
            l = (dy * dy) + (dx * dx);
            if (Math.abs(l) < JXG.Math.eps) {
                l = JXG.Math.eps;
            }
            x = ((d0 * dy) + (d1 * dx)) / l;
            y = ((d1 * dy) - (d0 * dx)) / l;
            n1s = n1 / s;
            firstPoint = new JXG.Coords(JXG.COORDS_BY_USER, [x + n1s * dx, y + n1s * dy], board);
            secondPoint = new JXG.Coords(JXG.COORDS_BY_USER, [x - n1s * dx, y - n1s * dy], board);
            d = circle.center.coords.distance(JXG.COORDS_BY_USER, firstPoint);

            if ((r < (d - 1)) || isNaN(d)) {
                return [0];
            } else {
                return [2,firstPoint,secondPoint];
            }
        }
        return [0];
    },

    /**
     * Calculates the coordinates of the intersection of the given circles.
     * @deprecated 
     * @param {JXG.Circle} circle1 Circle.
     * @param {JXG.Circle} circle2 Circle.
     * @param {JXG.Board} [board=circle1.board] Reference to the board
     * @returns {Array} Coordinates of the intersection points of the given circles and the
     * amount of intersection points in the first component of the array.
     */
    intersectCircleCircle: function(circle1, circle2, board) {
        var intersection = {},
            r1 = circle1.Radius(),
            r2 = circle2.Radius(),
            M1 = circle1.center.coords.usrCoords,
            M2 = circle2.center.coords.usrCoords,
            rSum, rDiff, s,
            dx, dy, a, h;

        if (!JXG.exists(board))
            board = circle1.board;

        rSum = r1 + r2;
        rDiff = Math.abs(r1 - r2);
        // Abstand der Mittelpunkte der beiden Kreise
        s = circle1.center.coords.distance(JXG.COORDS_BY_USER, circle2.center.coords);
        if (s > rSum) {
            return [0]; // Kreise schneiden sich nicht, liegen nebeneinander
        } else if (s < rDiff) {
            return [0]; // Kreise schneiden sich nicht, liegen ineinander
        } else {
            if (s != 0) {
                intersection[0] = 1; // es gibt einen Schnitt
                dx = M2[1] - M1[1];
                dy = M2[2] - M1[2];
                a = (s * s - r2 * r2 + r1 * r1) / (2 * s);
                h = Math.sqrt(r1 * r1 - a * a);
                intersection[1] = new JXG.Coords(JXG.COORDS_BY_USER,
                    [M1[1] + (a / s) * dx + (h / s) * dy,
                        M1[2] + (a / s) * dy - (h / s) * dx],
                    board);
                intersection[2] = new JXG.Coords(JXG.COORDS_BY_USER,
                    [M1[1] + (a / s) * dx - (h / s) * dy,
                        M1[2] + (a / s) * dy + (h / s) * dx],
                    board);
            } else {
                return [0]; // vorsichtshalber...
            }
            return intersection;
        }
    },

    /**
     * Computes the intersection of a pair of lines, circles or both.
     * It uses the internal data array stdform of these elements.
     * @param {Array} el1 stdform of the first element (line or circle)
     * @param {Array} el2 stdform of the second element (line or circle)
     * @param {Number} i Index of the intersection point that should be returned.
     * @param board Reference to the board.
     * @returns {JXG.Coords} Coordinates of one of the possible two or more intersection points.
     * Which point will be returned is determined by i.
     */
    meet: function(el1, el2, i, board) {
        var eps = JXG.Math.eps; //    var eps = 0.000001;
        if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) < eps) { // line line
            return this.meetLineLine(el1, el2, i, board);
        } else if (Math.abs(el1[3]) >= eps && Math.abs(el2[3]) < eps) { // circle line
            return this.meetLineCircle(el2, el1, i, board);
        } else if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) >= eps) { // line circle
            return this.meetLineCircle(el1, el2, i, board);
        } else {  // circle circle
            return this.meetCircleCircle(el1, el2, i, board);
        }
    },

    /**
     * Intersection of two lines using the stdform.
     * @param {Array} l1 stdform of the first line
     * @param {Array} l2 stdform of the second line
     * @param {number} i unused
     * @param {JXG.Board} board Reference to the board.
     * @returns {JXG.Coords} Coordinates of the intersection point.
     */
    meetLineLine: function(l1, l2, i, board) {
        var s = JXG.Math.crossProduct(l1, l2);
        if (Math.abs(s[0]) > JXG.Math.eps) {
            s[1] /= s[0];
            s[2] /= s[0];
            s[0] = 1.0;
        }
        return new JXG.Coords(JXG.COORDS_BY_USER, s, board);
    },

    /**
     * Intersection of line and circle using the stdform.
     * @param {Array} lin stdform of the line
     * @param {Array} circ stdform of the circle
     * @param {number} i number of the returned intersection point.
     *   i==0: use the positive square root,
     *   i==1: use the negative square root.
     * @param {JXG.Board} board Reference to a board.
     * @returns {JXG.Coords} Coordinates of the intersection point
     */
    meetLineCircle: function(lin, circ, i, board) {
        var a,b,c,d,n, A,B,C, k,t;
        if (circ[4] < JXG.Math.eps) { // Radius is zero, return center of circle
            if (Math.abs( JXG.Math.innerProduct([1,circ[6],circ[7]], lin, 3)) < JXG.Math.eps) {
                return new JXG.Coords(JXG.COORDS_BY_USER, circ.slice(6, 8), board);
            } else {
                return new JXG.Coords(JXG.COORDS_BY_USER, [NaN,NaN], board);
            }
        }
        c = circ[0];
        b = circ.slice(1, 3);
        a = circ[3];
        d = lin[0];
        n = lin.slice(1, 3);

        // Line is assumed to be normalized. Therefore, nn==1 and we can skip some operations:
        /*
         var nn = n[0]*n[0]+n[1]*n[1];
         A = a*nn;
         B = (b[0]*n[1]-b[1]*n[0])*nn;
         C = a*d*d - (b[0]*n[0]+b[1]*n[1])*d + c*nn;
         */
        A = a;
        B = (b[0] * n[1] - b[1] * n[0]);
        C = a * d * d - (b[0] * n[0] + b[1] * n[1]) * d + c;

        k = B * B - 4 * A * C;
        if (k >= 0) {
            k = Math.sqrt(k);
            t = [(-B + k) / (2 * A),(-B - k) / (2 * A)];
            return ((i == 0)
                ? new JXG.Coords(JXG.COORDS_BY_USER, [-t[0] * (-n[1]) - d * n[0],-t[0] * n[0] - d * n[1]], board)
                : new JXG.Coords(JXG.COORDS_BY_USER, [-t[1] * (-n[1]) - d * n[0],-t[1] * n[0] - d * n[1]], board)
                );
            /*
             new JXG.Coords(JXG.COORDS_BY_USER, [-t[0]*(-n[1])-d*n[0]/nn,-t[0]*n[0]-d*n[1]/nn], this.board),
             new JXG.Coords(JXG.COORDS_BY_USER, [-t[1]*(-n[1])-d*n[0]/nn,-t[1]*n[0]-d*n[1]/nn], this.board)
             */
        } else {
            return new JXG.Coords(JXG.COORDS_BY_USER, [0,0,0], board);
        }
        // Returns do not work with homogeneous coordinates, yet
    },

    /**
     * Intersection of two circles using the stdform.
     * @param {Array} circ1 stdform of the first circle
     * @param {Array} circ2 stdform of the second circle
     * @param {number} i number of the returned intersection point.
     *   i==0: use the positive square root,
     *   i==1: use the negative square root.
     * @param {JXG.Board} board Reference to the board.
     * @returns {JXG.Coords} Coordinates of the intersection point
     */
    meetCircleCircle: function(circ1, circ2, i, board) {
        var radicalAxis;
        if (circ1[4] < JXG.Math.eps) { // Radius are zero, return center of circle, if on other circle
            if (Math.abs(this.distance(circ1.slice(6, 2), circ2.slice(6, 8)) - circ2[4]) < JXG.Math.eps) {
                return new JXG.Coords(JXG.COORDS_BY_USER, circ1.slice(6, 8), board);
            } else {
                return new JXG.Coords(JXG.COORDS_BY_USER, [0,0,0], board);
            }
        }
        if (circ2[4] < JXG.Math.eps) { // Radius are zero, return center of circle, if on other circle
            if (Math.abs(this.distance(circ2.slice(6, 2), circ1.slice(6, 8)) - circ1[4]) < JXG.Math.eps) {
                return new JXG.Coords(JXG.COORDS_BY_USER, circ2.slice(6, 8), board);
            } else {
                return new JXG.Coords(JXG.COORDS_BY_USER, [0,0,0], board);
            }
        }
        radicalAxis = [circ2[3] * circ1[0] - circ1[3] * circ2[0],
            circ2[3] * circ1[1] - circ1[3] * circ2[1],
            circ2[3] * circ1[2] - circ1[3] * circ2[2],
            0,1,Infinity, Infinity, Infinity];
        radicalAxis = JXG.Math.normalize(radicalAxis);
        return this.meetLineCircle(radicalAxis, circ1, i, board);
        // Returns do not work with homogeneous coordinates, yet
    },

    /**
     * Compute an intersection of the curves c1 and c2
     * with a generalized Newton method.
     * We want to find values t1, t2 such that
     * c1(t1) = c2(t2), i.e.
     * (c1_x(t1)-c2_x(t2),c1_y(t1)-c2_y(t2)) = (0,0).
     * We set
     * (e,f) := (c1_x(t1)-c2_x(t2),c1_y(t1)-c2_y(t2))
     *
     * The Jacobian J is defined by
     * J = (a, b)
     *     (c, d)
     * where
     * a = c1_x'(t1)
     * b = -c2_x'(t2)
     * c = c1_y'(t1)
     * d = -c2_y'(t2)
     *
     * The inverse J^(-1) of J is equal to
     *  (d, -b)/
     *  (-c, a) / (ad-bc)
     *
     * Then, (t1new, t2new) := (t1,t2) - J^(-1)*(e,f).
     * If the function meetCurveCurve possesses the properties
     * t1memo and t2memo then these are taken as start values
     * for the Newton algorithm.
     * After stopping of the Newton algorithm the values of t1 and t2 are stored in
     * t1memo and t2memo.
     *
     * @param {JXG.Curve} c1 Curve, Line or Circle
     * @param {JXG.Curve} c2 Curve, Line or Circle
     * @param {Number} t1ini start value for t1
     * @param {Number} t2ini start value for t2
     * @param {JXG.Board} [board=c1.board] Reference to a board object.
     * @returns {JXG.Coords} intersection point
     */
    meetCurveCurve: function(c1, c2, t1ini, t2ini, board) {
        var count = 0,
            t1, t2,
            a, b, c, d, disc,
            e, f, F,
            D00, D01,
            D10, D11;

        if (!JXG.exists(board))
            board = c1.board;

        if (arguments.callee.t1memo) {
            t1 = arguments.callee.t1memo;
            t2 = arguments.callee.t2memo;
        } else {
            t1 = t1ini;
            t2 = t2ini;
        }

        /*
         if (t1>c1.maxX()) { t1 = c1.maxX(); }
         if (t1<c1.minX()) { t1 = c1.minX(); }
         if (t2>c2.maxX()) { t2 = c2.maxX(); }
         if (t2<c2.minX()) { t2 = c2.minX(); }
         */

        c1X = function(t) { return c1.X.apply(c1, [t]); };
        c1Y = function(t) { return c1.Y.apply(c1, [t]); };
        c2X = function(t) { return c2.X.apply(c2, [t]); };
        c2Y = function(t) { return c2.Y.apply(c2, [t]); };
         
        e = c1.X(t1) - c2.X(t2);
        f = c1.Y(t1) - c2.Y(t2);
        F = e * e + f * f;
        
        D00 = board.D(c1.X, c1);
        D01 = board.D(c2.X, c2);
        D10 = board.D(c1.Y, c1);
        D11 = board.D(c2.Y, c2);
        
        while (F > JXG.Math.eps && count < 10) {
            a = D00(t1);
            b = -D01(t2);
            c = D10(t1);
            d = -D11(t2);
            disc = a * d - b * c;
            t1 -= (d * e - b * f) / disc;
            t2 -= (a * f - c * e) / disc;
            e = c1.X(t1) - c2.X(t2);
            f = c1.Y(t1) - c2.Y(t2);
            F = e * e + f * f;
            count++;
        }
        //console.log(t1+' '+t2);

        arguments.callee.t1memo = t1;
        arguments.callee.t2memo = t2;

        //return (new JXG.Coords(JXG.COORDS_BY_USER, [2,2], this.board));
        if (Math.abs(t1) < Math.abs(t2)) {
            return (new JXG.Coords(JXG.COORDS_BY_USER, [c1.X(t1),c1.Y(t1)], board));
        } else {
            return (new JXG.Coords(JXG.COORDS_BY_USER, [c2.X(t2),c2.Y(t2)], board));
        }
    },

    /**
     * Intersection of curve with line,
     * Order of input does not matter for el1 and el2.
     * @param {JXG.Curve,JXG.Line} el1 Curve or Line
     * @param {JXG.Curve,JXG.Line} el2 Curve or Line
     * @param {Number} nr the nr-th intersection point will be returned.
     * @param {JXG.Board} [board=el1.board] Reference to a board object.
     * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,
     * the ideal point [0,1,0] is returned.
     */
    meetCurveLine: function(el1, el2, nr, board, pointObj) {
        var v = [0, NaN, NaN], i, cu, li;

        if (!JXG.exists(board)) {
            board = el1.board;
        }

        for (i = 0; i <= 1; i++) {
            if (arguments[i].elementClass == JXG.OBJECT_CLASS_CURVE) {
                cu = arguments[i];
            } else if (arguments[i].elementClass == JXG.OBJECT_CLASS_LINE) {
                li = arguments[i];
            } else
                throw new Error("JSXGraph: Can't call meetCurveLine with parent class " + (arguments[i].elementClass) + ".");
        }

        if (cu.visProp.curvetype==='plot') {
            v = this.meetCurveLineDiscrete(cu, li, nr, board, pointObj);
        } else {
            v = this.meetCurveLineContinuous(cu, li, nr, board);
        }

        return v;
    },
    
    /**
     * Intersection of line and curve, continuous case.
     * Segments are treated as lines. Finding the nr-the intersection point
     * works for nr=0,1 only.
     * 
     * BUG: does not respect cu.minX() and cu.maxX() 
     */
    meetCurveLineContinuous: function(cu, li, nr, board) {
        var t, t2, i, cu, li, func, z,
            tnew, steps, delta, tstart, tend, cux, cuy;

        func = function(t) {
            return li.stdform[0] + li.stdform[1] * cu.X(t) + li.stdform[2] * cu.Y(t);
        };
        
        /**
         * Find some intersection point
         */
        if (arguments.callee.t1memo) {
            tstart = arguments.callee.t1memo;
            t = JXG.Math.Numerics.root(func, tstart);
        } else {
            tstart = cu.minX();
            tend = cu.maxX();
            t = JXG.Math.Numerics.root(func, [tstart,tend]);
        }
        arguments.callee.t1memo = t;
        cux = cu.X(t);
        cuy = cu.Y(t);

        /**
         * Find second intersection point
         */
        if (nr == 1) {
            if (arguments.callee.t2memo) {
                tstart = arguments.callee.t2memo;
                t2 = JXG.Math.Numerics.root(func, tstart);
            }
            if (!(Math.abs(t2 - t) > 0.1 && Math.abs(cux - cu.X(t2)) > 0.1 && Math.abs(cuy - cu.Y(t2)) > 0.1)) {
                steps = 20;
                delta = (cu.maxX() - cu.minX()) / steps;
                tnew = cu.minX();
                for (i = 0; i < steps; i++) {
                    t2 = JXG.Math.Numerics.root(func, [tnew,tnew + delta]);
                    if (Math.abs(t2 - t) > 0.1 && Math.abs(cux - cu.X(t2)) > 0.1 && Math.abs(cuy - cu.Y(t2)) > 0.1) {
                        break;
                    }
                    tnew += delta;
                }
            }
            t = t2;
            arguments.callee.t2memo = t;
        }

        if (Math.abs(func(t)) > JXG.Math.eps) {
            z = NaN;
        } else {
            z = 1.0;
        }
        return (new JXG.Coords(JXG.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board));
    },

    /**
     * Intersection of line and curve, continuous case.
     * Segments are treated as lines. 
     * Finding the nr-the intersection point should work for all nr.
     */
    meetCurveLineDiscrete: function(cu, li, nr, board, pointObj) {
        var len, i, p1, p2, q,
            d, cnt = 0, res, 
            p, testSegment = false;

        len = cu.numberPoints; 
        if (pointObj!=null) {
            p = pointObj.point;
            if (JXG.exists(p) && !p.visProp.alwaysintersect) {
                testSegment = true;
            }
            
        }
    
        // In case, no intersection will be found we will take this
        q = new JXG.Coords(JXG.COORDS_BY_USER, [0, NaN, NaN], board);
        
        p2 = [1, cu.X(0), cu.Y(0)];
        for (i=1;i<len;i++) {
            p1 = p2.slice(0);
            p2 = [1, cu.X(i), cu.Y(i)];
            d = this.distance(p1, p2);
            if (d<JXG.Math.eps) {    // The defining points are identical
                continue;
            }
            res = this.meetSegmentSegment(p1, p2, li.point1.coords.usrCoords, li.point2.coords.usrCoords, board);
            if (0<=res[1] && res[1]<=1) {
                if (cnt==nr) {
                    
                    /**
                     * If the intersection point is not part of the segment, 
                     * this intersection point is set to non-existent.
                     * This prevents jumping of the intersection points.
                     * But it may be discussed if it is the desired behavior.
                     */
                    if (testSegment 
                        && ( li.visProp.straightfirst==false && res[2]<0 
                             || li.visProp.straightlast==false && res[2]>1 )
                        ) {
                        break;
                    }
                        
                    q = new JXG.Coords(JXG.COORDS_BY_USER, res[0], board);
                    break;
                }
                cnt++;
            }
        }

        return q;
    },

    /**
     * Intersection of two segments.
     * @param {Array} p1 First point of segment 1 using homogeneous coordinates [z,x,y]
     * @param {Array} p2 Second point of segment 1 using homogeneous coordinates [z,x,y]
     * @param {Array} q1 First point of segment 2 using homogeneous coordinates [z,x,y]
     * @param {Array} q2 Second point of segment 2 using homogeneous coordinates [z,x,y]
     * @returns {Array} [Intersection point, t, u] The first entry contains the homogeneous coordinates 
     * of the intersection point. The second and third entry gives the position of the intersection between the two defining points.
     * For example, the second entry t is defined by: interestion point = t*p1 + (1-t)*p2.
     **/
    meetSegmentSegment: function(p1, p2, q1, q2, board) {
        var li1 = JXG.Math.crossProduct(p1, p2),
            li2 = JXG.Math.crossProduct(q1, q2),
            c = JXG.Math.crossProduct(li1, li2),
            denom = c[0],
            t, u, diff;
        
        if (Math.abs(denom)<Math.eps) {
            return [c, Number.Infinity, Number.Infinity];
        }

        diff = [q1[1]-p1[1], q1[2]-p1[2]];
        // Because of speed issues, evalute the determinants directly
        //t = JXG.Math.Numerics.det([diff, [p2[1]-p1[1], p2[2]-p1[2]] ]) / denom;
        //u = JXG.Math.Numerics.det([diff, [q2[1]-q1[1], q2[2]-q1[2]] ]) / denom;
        t = (diff[0]*(q2[2]-q1[2]) - diff[1]*(q2[1]-q1[1])) / denom;
        u = (diff[0]*(p2[2]-p1[2]) - diff[1]*(p2[1]-p1[1])) / denom;
        
        return [c, t, u];
    },
    
    /****************************************/
    /****           PROJECTIONS          ****/
    /****************************************/

    /**
     * Calculates the coordinates of the projection of a given point on a given circle. I.o.w. the
     * nearest one of the two intersection points of the line through the given point and the circles
     * center.
     * @param {JXG.Point_JXG.Coords} point Point to project or coords object to project.
     * @param {JXG.Circle} circle Circle on that the point is projected.
     * @param {JXG.Board} [board=point.board] Reference to the board
     * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.
     */
    projectPointToCircle: function(point, circle, board) {
        var dist, P,
            M = circle.center.coords.usrCoords,
            x, y, factor;

        if (!JXG.exists(board)) {
            board = point.board;
        }

        if (JXG.isPoint(point))  {
            dist = point.coords.distance(JXG.COORDS_BY_USER, circle.center.coords);
            P = point.coords.usrCoords;
        } else {  // coords
            dist = point.distance(JXG.COORDS_BY_USER, circle.center.coords);
            P = point.usrCoords;
        }

        if (Math.abs(dist) < JXG.Math.eps) {
            dist = JXG.Math.eps;
        }
        factor = circle.Radius() / dist;
        x = M[1] + factor * (P[1] - M[1]);
        y = M[2] + factor * (P[2] - M[2]);

        return new JXG.Coords(JXG.COORDS_BY_USER, [x, y], board);
    },

    /**
     * Calculates the coordinates of the orthogonal projection of a given point on a given line. I.o.w. the
     * intersection point of the given line and its perpendicular through the given point.
     * @param {JXG.Point} point Point to project.
     * @param {JXG.Line} line Line on that the point is projected.
     * @param {JXG.Board} [board=point.board] Reference to a board.
     * @returns {JXG.Coords} The coordinates of the projection of the given point on the given line.
     */
    projectPointToLine: function(point, line, board) {
        // Homogeneous version
        var v = [0,line.stdform[1],line.stdform[2]];

        if (!JXG.exists(board))
            board = point.board;

        v = JXG.Math.crossProduct(v, point.coords.usrCoords);

        return this.meetLineLine(v, line.stdform, 0, board);
    },

    /**
     * Calculates the coordinates of the orthogonal projection of a given coordinate array on a given line
     * segment defined by two coordinate arrays. 
     * @param {Array} p1 Point to project.
     * @param {Array} q1 Start point of the line segment on that the point is projected.
     * @param {Array} q2 End point of the line segment on that the point is projected.
     * @returns {Array} The coordinates of the projection of the given point on the given segment 
     * and the factor that determines the projected point as a convex combination of the 
     * two endpoints q1 and q2 of the segment.     
     */
    projectCoordsToSegment: function(p, q1, q2) {
        var s = [q2[1]-q1[1], q2[2]-q1[2]],
            v = [p[1]-q1[1], p[2]-q1[2]],
            t, denom, c;
            
        /**
         * If the segment has length 0, i.e. is a point,
         * the projection is equal to that point.
         */
        if (Math.abs(s[0])<JXG.Math.eps && Math.abs(s[1])<JXG.Math.eps) {
            return q1;
        }
        t = JXG.Math.innerProduct(v,s);
        denom = JXG.Math.innerProduct(s,s);
        t /= denom;
        return [ [1, t*s[0]+q1[1], t*s[1]+q1[2]], t];
    },
    
    /**
     * Calculates the coordinates of the projection of a given point on a given curve.
     * Uses {@link #projectCoordsToCurve}.
     * @param {JXG.Point} point Point to project.
     * @param {JXG.Curve} curve Curve on that the point is projected.
     * @param {JXG.Board} [board=point.board] Reference to a board.
     * @see #projectCoordsToCurve
     * @returns {JXG.Coords} The coordinates of the projection of the given point on the given graph.
     */
    projectPointToCurve: function(point, curve, board) {
        if (!JXG.exists(board))
            board = point.board;

        var x = point.X(),
            y = point.Y(),
            t = point.position || 0.0, //(curve.minX()+curve.maxX())*0.5,
            result = this.projectCoordsToCurve(x, y, t, curve, board);

        point.position = result[1];      // side effect !
        return result[0];
    },

    /**
     * Calculates the coordinates of the projection of a coordinates pair on a given curve. In case of
     * function graphs this is the
     * intersection point of the curve and the parallel to y-axis through the given point.
     * @param {Number} x coordinate to project.
     * @param {Number} y coordinate to project.
     * @param {Number} t start value for newtons method
     * @param {JXG.Curve} curve Curve on that the point is projected.
     * @param {JXG.Board} [board=curve.board] Reference to a board.
     * @see #projectPointToCurve
     * @returns {JXG.Coords} Array containing the coordinates of the projection of the given point on the given graph and
     * the position on the curve.
     */
    projectCoordsToCurve: function(x, y, t, curve, board) {
        var newCoords, i, 
            x0, y0, x1, y1, mindist, dist, lbda, li, v, coords, d,
            p1, p2, q1, q2, res,
            infty = Number.POSITIVE_INFINITY, 
            minfunc, t, tnew, fnew, fold, delta, steps;

        if (!JXG.exists(board)) {
            board = curve.board;
        }
        
        if (curve.visProp.curvetype == 'parameter' || curve.visProp.curvetype == 'polar') {
            // Function to minimize
            minfunc = function(t) {
                var dx = x - curve.X(t),
                    dy = y - curve.Y(t);
                return dx * dx + dy * dy;
            };

            fold = minfunc(t);
            steps = 20;
            delta = (curve.maxX() - curve.minX()) / steps;
            tnew = curve.minX();
            for (i = 0; i < steps; i++) {
                fnew = minfunc(tnew);
                if (fnew < fold) {
                    t = tnew;
                    fold = fnew;
                }
                tnew += delta;
            }
            t = JXG.Math.Numerics.root(JXG.Math.Numerics.D(minfunc), t);

            if (t < curve.minX()) {
                t = curve.maxX() + t - curve.minX();
            } // Cyclically
            if (t > curve.maxX()) {
                t = curve.minX() + t - curve.maxX();
            }
            newCoords = new JXG.Coords(JXG.COORDS_BY_USER, [curve.X(t),curve.Y(t)], board);
        } else if (curve.visProp.curvetype == 'plot') {
            t = 0;
            mindist = infty;
            if (curve.numberPoints==0) {
                newCoords = [0,1,1]; 
            } else {
                newCoords = [curve.Z(0), curve.X(0), curve.Y(0)]; 
            } 
            
            if (curve.numberPoints>1) {
                p1 = [curve.Z(0), curve.X(0), curve.Y(0)];
                for (i=0; i<curve.numberPoints-1; i++) {
                    p2 = [curve.Z(i+1), curve.X(i+1), curve.Y(i+1)];
                    v = [1, x, y];
                    res = this.projectCoordsToSegment(v, p1, p2);
                    lbda = res[1];
                    coords = res[0];
                    if (0.0<=lbda && lbda<=1.0) {     
                        dist = this.distance(coords, v);
                        d = i + lbda;
                    } else if (lbda<0.0) {
                        coords = p1; 
                        dist = this.distance(p1, v);
                        d = i;
                    } else if (lbda>1.0 && i+1== curve.numberPoints-1) {
                        coords = p2;
                        dist = this.distance(coords, v);
                        d = curve.numberPoints-1;
                    }
                    
                    if (dist < mindist) {
                        mindist = dist;
                        t = d;
                        newCoords = coords;
                    }
                    p1 = p2;  // Moving on.
                }
            }
           
            newCoords = new JXG.Coords(JXG.COORDS_BY_USER, newCoords, board);
        } else {             // functiongraph
            t = x;
            x = t; //curve.X(t);
            y = curve.Y(t);
            newCoords = new JXG.Coords(JXG.COORDS_BY_USER, [x,y], board);
        }
        return [curve.updateTransform(newCoords), t];
    },

    /**
     * Calculates the coordinates of the projection of a given point on a given turtle. A turtle consists of
     * one or more curves of curveType 'plot'. Uses {@link #projectPointToCurve}.
     * @param {JXG.Point} point Point to project.
     * @param {JXG.Turtle} turtle on that the point is projected.
     * @param {JXG.Board} [board=point.board] Reference to a board.
     * @returns {JXG.Coords} The coordinates of the projection of the given point on the given turtle.
     */
    projectPointToTurtle: function(point, turtle, board) {
        var newCoords, t, x, y, i,
            np = 0,
            npmin = 0,
            mindist = Number.POSITIVE_INFINITY,
            dist, el, minEl,
            len = turtle.objects.length;

        if (!JXG.exists(board))
            board = point.board;

        for (i = 0; i < len; i++) {  // run through all curves of this turtle
            el = turtle.objects[i];
            if (el.elementClass == JXG.OBJECT_CLASS_CURVE) {
                newCoords = this.projectPointToCurve(point, el);
                dist = this.distance(newCoords.usrCoords, point.coords.usrCoords);
                if (dist < mindist) {
                    x = newCoords.usrCoords[1];
                    y = newCoords.usrCoords[2];
                    t = point.position;
                    mindist = dist;
                    minEl = el;
                    npmin = np;
                }
                np += el.numberPoints;
            }
        }
        newCoords = new JXG.Coords(JXG.COORDS_BY_USER, [x,y], board);
        point.position = t + npmin;
        return minEl.updateTransform(newCoords);
    },

    /**
     * Trivial projection of a point to another point.
     * @param {JXG.Point} point Point to project (not used).
     * @param {JXG.Point} dest Point on that the point is projected.
     * @param {JXG.Board} [board=point.board] Reference to the board (not used).
     * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.
     */
    projectPointToPoint: function(point, dest, board) {
        return dest.coords;
    },
    
    /**
     * Calculates the distance of a point to a line. The point and the line are given by homogeneous 
     * coordinates. For lines this can be line.stdform.
     * @param {Array} point Homogeneous coordinates of a point.
     * @param {Array} line Homogeneous coordinates of a line ([C,A,B] where A*x+B*y+C*z=0).
     * @returns {Number} Distance of the point to the line.
     */
    distPointLine: function(point, line) {
        var a = line[1],
            b = line[2],
            c = line[0],
            nom;
        
        if (Math.abs(a)+Math.abs(b) < JXG.Math.eps) {
            return Number.POSITIVE_INFINITY;
        }
        
        nom = a*point[1] + b*point[2] + c*1;
        a *= a;
        b *= b;
        return Math.abs(nom) / Math.sqrt(a+b);
    }
    
});


/*
 Copyright 2008-2011
 Matthias Ehmann,
 Michael Gerhaeuser,
 Carsten Miller,
 Bianca Valentin,
 Alfred Wassermann,
 Peter Wilfahrt

 This file is part of JSXGraph.

 JSXGraph is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 JSXGraph is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @fileoverview In this file the namespace Math.Poly is defined, which holds algorithms to create and
 * manipulate polynomials.
 */


/**
 * The JXG.Math.Poly namespace holds algorithms to create and manipulate polynomials.
 * @namespace
 */
JXG.Math.Poly = {};

/**
 * Define a polynomial ring over R.
 * @class
 * @param {Array} variables List of indeterminates.
 */
JXG.Math.Poly.Ring = function (variables) {
    /**
     * A list of variables in this polynomial ring.
     * @type Array
     */
    this.vars = variables;
};

JXG.extend(JXG.Math.Poly.Ring.prototype, /** @lends JXG.Math.Poly.Ring.prototype */ {
    // nothing yet.
});


/**
 * Define a monomial over the polynomial ring <tt>ring</tt>.
 * @class
 * @param {JXG.Math.Poly.Ring} ring
 * @param {Number} coefficient
 * @param {Array} exponents An array of exponents, corresponding to ring
 */
JXG.Math.Poly.Monomial = function (ring, coefficient, exponents) {
    var i;

    if (!JXG.exists(ring)) {
        throw new Error('JSXGraph error: In JXG.Math.Poly.monomial missing parameter \'ring\'.');
    }

    if (!JXG.isArray(exponents)) {
        exponents = [];
    }

    exponents = exponents.slice(0, ring.vars.length);

    for (i = exponents.length; i < ring.vars.length; i++) {
        exponents.push(0);
    }

    /**
     * A polynomial ring.
     * @type JXG.Math.Poly.Ring
     */
    this.ring = ring;

    /**
     * The monomial's coefficient
     * @type Number
     */
    this.coefficient = coefficient || 0;

    /**
     * Exponent vector, the order depends on the order of the variables
     * in the ring definition.
     * @type Array
     */
    this.exponents = JXG.deepCopy(exponents);
};

JXG.extend(JXG.Math.Poly.Monomial.prototype, /** @lends JXG.Math.Poly.Monomial.prototype */ {

    /**
     * Creates a deep copy of the monomial.
     * @returns {JXG.Math.Poly.Monomial}
     */
    copy: function () {
        return new JXG.Math.Poly.Monomial(this.ring, this.coefficient, this.exponents);
    },

    /**
     * Print the monomial.
     * @returns {String} String representation of the monomial
     */
    print: function () {
        var s = [],
            i;

        for (i = 0; i < this.ring.vars.length; i++) {
            s.push(this.ring.vars[i] + '^' + this.exponents[i]);
        }

        return this.coefficient + '*' + s.join('*');
    }
});


/**
 * A polynomial is a sum of monomials.
 * @class
 * @param {JXG.Math.Poly.Ring} ring A polynomial ring.
 * @param {String} str TODO String representation of the polynomial, will be parsed.
 */
JXG.Math.Poly.Polynomial = function (ring, str) {
    var parse = function () {

    },
    mons;

    if (!JXG.exists(ring)) {
        throw new Error('JSXGraph error: In JXG.Math.Poly.polynomial missing parameter \'ring\'.');
    }

    if (JXG.exists(str) && typeof str === 'string') {
        mons = parse(str);
    } else {
        mons = [];
    }

    /**
     * A polynomial ring.
     * @type JXG.Math.Poly.Ring
     */
    this.ring = ring;

    /**
     * List of monomials.
     * @type Array
     */
    this.monomials = mons;
};

JXG.extend(JXG.Math.Poly.Polynomial.prototype, /** @lends JXG.Math.Poly.Polynomial.prototype */ {
    /**
     * Find a monomial with the given signature, i.e. exponent vector.
     * @param {Array} sig An array of numbers
     * @returns {Number} The index of the first monomial with the given signature, or -1
     * if no monomial could be found.
     */
    findSignature: function (sig) {
        var i;

        for (i = 0; i < this.monomials.length; i++) {
            if (JXG.cmpArrays(this.monomials[i].exponents, sig)) {
                return i;
            }
        }

        return -1;
    },

    /**
     * Adds a monomial to the polynomial. Checks the existing monomials for the added
     * monomial's signature and just adds the coefficient if one is found.
     * @param {JXG.Math.Poly.Monomial} m
     * @param {Number} factor Either <tt>1</tt> or <tt>-1</tt>.
     */
    addSubMonomial: function (m, factor) {
        var i;

        i = this.findSignature(m.exponents);
        if (i > -1) {
            this.monomials[i].coefficient += factor*m.coefficient;
        } else {
            m.coefficient *= factor;
            this.monomials.push(m);
        }
    },

    /**
     * Adds another polynomial or monomial to this one and merges them by checking for the
     * signature of each new monomial in the existing monomials.
     * @param {JXG.Math.Poly.Polynomial|JXG.Math.Poly.Monomial} mp
     */
    add: function (mp) {
        var i;

        if (JXG.exists(mp) && mp.ring === this.ring) {
            if (JXG.isArray(mp.exponents)) {
                // mp is a monomial
                this.addSubMonomial(mp, 1);
            } else {
                // mp is a polynomial
                for (i = 0; i < mp.monomials.length; i++) {
                    this.addSubMonomial(mp.monomials[i], 1);
                }
            }
        } else {
            throw new Error('JSXGraph error: In JXG.Math.Poly.polynomial.add either summand is undefined or rings don\'t match.');
        }
    },

    /**
     * Subtracts another polynomial or monomial from this one and merges them by checking for the
     * signature of each new monomial in the existing monomials.
     * @param {JXG.Math.Poly.Polynomial|JXG.Math.Poly.Monomial} mp
     */
    sub: function (mp) {
        var i;

        if (JXG.exists(mp) && mp.ring === this.ring) {
            if (JXG.isArray(mp.exponents)) {
                // mp is a monomial
                this.addSubMonomial(mp, -1);
            } else {
                // mp is a polynomial
                for (i = 0; i < mp.monomials.length; i++) {
                    this.addSubMonomial(mp.monomials[i], -1);
                }
            }
        } else {
            throw new Error('JSXGraph error: In JXG.Math.Poly.polynomial.sub either summand is undefined or rings don\'t match.');
        }
    },

    /**
     * Creates a deep copy of the polynomial.
     * @returns {JXG.Math.Poly.Polynomial}
     */
    copy: function () {
        var i, p;

        p = new JXG.Math.Poly.Polynomial(this.ring);

        for (i = 0; i < this.monomials.length; i++) {
            p.monomials.push(this.monomials[i].copy());
        }
        return p;
    },

    /**
     * Prints the polynomial.
     * @returns {String} A string representation of the polynomial.
     */
    print: function () {
        var s = [],
            i;

        for (i = 0; i < this.monomials.length; i++) {
            s.push('(' + this.monomials[i].print() + ')');
        }

        return s.join('+');
    }
});

/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/


/**
 * @fileoverview A class for complex arithmetics JXG.Complex is defined in this
 * file. Also a namespace JXG.C is included to provide instance-independent
 * arithmetic functions.
 * @author graphjs
 */

/**
 * Creates a new complex number.
 * @class This class is for calculating with complex numbers.
 * @param [x=0] Real part of the resulting complex number.
 * @param [y=0] Imaginary part of the resulting complex number.
 * @returns An object representing the complex number <tt>x + iy</tt>.
 */
JXG.Complex = function(/** number */ x, /** number */ y) {
	/**
	 * This property is only to signalize that this object is of type JXG.Complex. Only
	 * used internally to distinguish between normal JavaScript numbers and JXG.Complex numbers.
	 * @type boolean
	 * @default true
	 * @private
	 */
    this.isComplex = true;
    
    if (typeof x == 'undefined') {
        x = 0;
    }
    if (typeof y == 'undefined') {
        y = 0;
    }

    /* is the first argument a complex number? if it is,
     * extract real and imaginary part. */
    if (x.isComplex) {
        y = x.imaginary;
        x = x.real;
    }

    /**
     * Real part of the complex number.
     * @type number
     * @default 0
     */
    this.real = x;

    /**
     * Imaginary part of the complex number.
     * @type number
     * @default 0
     */
    this.imaginary = y;

    /**
     * Absolute value in the polar form of the complex number. Currently unused.
     * @type number
     */
    this.absval = 0;

    /**
     * Angle value in the polar form of the complex number. Currently unused.
     * @type number
     */
    this.angle = 0;
};

JXG.extend(JXG.Complex.prototype, /** @lends JXG.Complex.prototype */ {
    /**
     * Converts a complex number into a string.
     * @return Formatted string containing the complex number in human readable form (algebraic form).
     */
    toString: function() /** string */{
        return '' + this.real + ' + ' + this.imaginary + 'i';
    },

    /**
     * Add another complex number to this complex number.
     * @param c A JavaScript number or a JXG.Complex object to be added to the current object.
     */
    add: function(/** JXG.Complex,number */ c) /** undefined */ {
        if(typeof c == 'number') {
            this.real += c;
        } else {
            this.real += c.real;
            this.imaginary += c.imaginary;
        }
    },

    /**
     * Subtract another complex number from this complex number.
     * @param c A JavaScript number or a JXG.Complex object to subtract from the current object.
     */
    sub: function(/** JXG.Complex,number */ c) /** undefined */{
        if(typeof c == 'number') {
            this.real -= c;
        } else {
            this.real -= c.real;
            this.imaginary -= c.imaginary;
        }
    },

    /**
     * Multiply another complex number to this complex number.
     * @param c A JavaScript number or a JXG.Complex object to
     * multiply with the current object.
     */
    mult: function(/** JXG.Complex,number */ c) /** undefined */{
        var re, im;
        if(typeof c == 'number') {
            this.real *= c;
            this.imaginary *= c;
        } else {
            re = this.real;
            im = this.imaginary;
            //  (a+ib)(x+iy) = ax-by + i(xb+ay)
            this.real = re*c.real - im*c.imaginary;
            this.imaginary = re*c.imaginary + im*c.real;
        }
    },

    /**
     * Divide this complex number by the given complex number.
     * @param c A JavaScript number or a JXG.Complex object to
     * divide the current object by.
     */
    div: function(/** JXG.Complex,number */ c) /** undefined */{
        var denom, im, re;

        if(typeof c == 'number') {
            if(Math.abs(c) < Math.eps) {
                this.real = Infinity;
                this.imaginary = Infinity;
                
                return;
            }
            this.real /= c;
            this.imaginary /= c;
        } else {
            //  (a+ib)(x+iy) = ax-by + i(xb+ay)
            if( (Math.abs(c.real) < Math.eps) && (Math.abs(c.imaginary) < Math.eps) ){
                this.real = Infinity;
                this.imaginary = Infinity;

                return;
            }

            denom = c.real*c.real + c.imaginary*c.imaginary;

            re = this.real;
            im = this.imaginary;
            this.real = (re*c.real + im*c.imaginary)/denom;
            this.imaginary = (im*c.real - re*c.imaginary)/denom;
        }
    },

    /**
     * Conjugate a complex number in place.
     * @param c A JavaScript number or a JXG.Complex object 
     */
    conj: function() /** undefined */ {
        this.imaginary *= -1;
    }
});

/**
 * @description
 * JXG.C is the complex number (name)space. It provides functions to calculate with
 * complex numbers (defined in {@link JXG.Complex}). With this namespace you don't have to modify
 * your existing complex numbers, e.g. to add two complex numbers:
 * <pre class="code">   var z1 = new JXG.Complex(1, 0);
 *    var z2 = new JXG.Complex(0, 1);
 *    z = JXG.C.add(z1, z1);</pre>
 * z1 and z2 here remain unmodified. With the object oriented approach above this
 * section the code would look like:
 * <pre class="code">   var z1 = new JXG.Complex(1, 0);
 *    var z2 = new JXG.Complex(0, 1);
 *    var z = new JXG.Complex(z1);
 *    z.add(z2);</pre>
 * @namespace Namespace for the complex number arithmetic functions.
 */
JXG.C = {};

/**
 * Add two (complex) numbers z1 and z2 and return the result as a (complex) number.
 * @param z1 Summand
 * @param z2 Summand
 * @return A complex number equal to the sum of the given parameters.
 */
JXG.C.add = function(/** JXG.Complex,number */ z1, /** JXG.Complex,number */ z2) /** JXG.Complex */{
    var z = new JXG.Complex(z1);
    z.add(z2);
    return z;
};

/**
 * Subtract two (complex) numbers z1 and z2 and return the result as a (complex) number.
 * @param z1 Minuend
 * @param z2 Subtrahend
 * @return A complex number equal to the difference of the given parameters.
 */
JXG.C.sub = function(/** JXG.Complex,number */ z1, /** JXG.Complex,number */ z2) /** JXG.Complex */{
    var z = new JXG.Complex(z1);
    z.sub(z2);
    return z;
};

/**
 * Multiply two (complex) numbers z1 and z2 and return the result as a (complex) number.
 * @param z1 Factor
 * @param z2 Factor
 * @return A complex number equal to the product of the given parameters.
 */
JXG.C.mult = function(/** JXG.Complex,number */ z1, /** JXG.Complex,number */ z2) /** JXG.Complex */{
    var z = new JXG.Complex(z1);
    z.mult(z2);
    return z;
};

/**
 * Divide two (complex) numbers z1 and z2 and return the result as a (complex) number.
 * @param z1 Dividend
 * @param z2 Divisor
 * @return A complex number equal to the quotient of the given parameters.
 */
JXG.C.div = function(/** JXG.Complex,number */ z1, /** JXG.Complex,number */ z2) /** JXG.Complex */{
    var z = new JXG.Complex(z1);
    z.div(z2);
    return z;
};

/**
 * Conjugate a complex number and return the result.
 * @param z1 Complex number
 * @return A complex number equal to the conjugate of the given parameter.
 */
JXG.C.conj = function(/** JXG.Complex,number */ z1) /** JXG.Complex */{
    var z = new JXG.Complex(z1);
    z.conj();
    return z;
};

/**
 * Absolute value of a complex number.
 * @param z1 Complex number
 * @return real number equal to the absolute value of the given parameter.
 */
JXG.C.abs = function(/** JXG.Complex,number */ z1) /** JXG.Complex */{
    var z = new JXG.Complex(z1);
    z.conj();
    z.mult(z1);
    return Math.sqrt(z.real);
};



/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.

*/

/*global JXG: true, AMprocessNode: true, MathJax: true, document: true */

/**
 * @fileoverview JSXGraph can use various technologies to render the contents of a construction, e.g.
 * SVG, VML, and HTML5 Canvas. To accomplish this, The rendering and the logic and control mechanisms
 * are completely separated from each other. Every rendering technology has it's own class, called
 * Renderer, e.g. SVGRenderer for SVG, the same for VML and Canvas. The common base for all available
 * renderers is the class AbstractRenderer defined in this file.
 */

/**
 * <p>This class defines the interface to the graphics part of JSXGraph. This class is an abstract class, it
 * actually does not render anything. This is up to the {@link JXG.SVGRenderer}, {@link JXG.VMLRenderer},
 * and {@link JXG.CanvasRenderer} classes. We strongly discourage you from using the methods in these classes
 * directly. Only the methods which are defined in this class and are not marked as private are guaranteed
 * to exist in any renderer instance you can access via {@link JXG.Board#renderer}. But not all methods may
 * work as expected.</p>
 * <p>The methods of this renderer can be divided into different categories:
 * <dl>
 *     <dt>Draw basic elements</dt>
 *     <dd>In this category we find methods to draw basic elements like {@link JXG.Point}, {@link JXG.Line},
 *     and {@link JXG.Curve} as well as assisting methods tightly bound to these basic painters. You do not
 *     need to implement these methods in a descendant renderer but instead implement the primitive drawing
 *     methods described below. This approach is encouraged when you're using a XML based rendering engine
 *     like VML and SVG. If you want to use a bitmap based rendering technique you are supposed to override
 *     these methods instead of the primitive drawing methods.</dd>
 *     <dt>Draw primitives</dt>
 *     <dd>This category summarizes methods to handle primitive nodes. As creation and management of these nodes
 *     is different among different the rendering techniques most of these methods are purely virtual and need
 *     proper implementation if you choose to not overwrite the basic element drawing methods.</dd>
 *     <dt>Attribute manipulation</dt>
 *     <dd>In XML based renders you have to manipulate XML nodes and their attributes to change the graphics.
 *     For that purpose attribute manipulation methods are defined to set the color, opacity, and other things.
 *     Please note that some of these methods are required in bitmap based renderers, too, because some elements
 *     like {@link JXG.Text} can be HTML nodes floating over the construction.</dd>
 *     <dt>Renderer control</dt>
 *     <dd>Methods to clear the drawing board or to stop and to resume the rendering engine.</dd>
 * </dl></p>
 * @class JXG.AbstractRenderer
 * @see JXG.SVGRenderer
 * @see JXG.VMLRenderer
 * @see JXG.CanvasRenderer
 */
JXG.AbstractRenderer = function () {

    // WHY THIS IS A CLASS INSTEAD OF A SINGLETON OBJECT:
    //
    // The renderers need to keep track of some stuff which is not always the same on different boards,
    // like enhancedRendering, reference to the container object, and resolution in VML. Sure, those
    // things could be stored in board. But they are rendering related and JXG.Board is already very
    // very big.
    //
    // And we can't save the rendering related data in {SVG,VML,Canvas}Renderer and make only the
    // JXG.AbstractRenderer a singleton because of that:
    //
    // Given an object o with property a set to true
    //     var o = {a: true};
    // and a class c doing nothing
    //     c = function() {};
    // Set c's prototype to o
    //     c.prototype = o;
    // and create an instance of c we get i.a to be true
    //     i = new c();
    //     i.a;
    //     > true
    // But we can overwrite this property via
    //     c.prototype.a = false;
    //     i.a;
    //     > false

    /**
     * The vertical offset for {@link Text} elements. Every {@link Text} element will
     * be placed this amount of pixels below the user given coordinates.
     * @type number
     * @default 8
     */
    this.vOffsetText = 0;

    /**
     * If this property is set to <tt>true</tt> the visual properties of the elements are updated
     * on every update. Visual properties means: All the stuff stored in the
     * {@link JXG.GeometryElement#visProp} property won't be set if enhancedRendering is <tt>false</tt>
     * @type Boolean
     * @default true
     */
    this.enhancedRendering = true;

    /**
     * The HTML element that stores the JSXGraph board in it.
     * @type Node
     */
    this.container = null;

    /**
     * This is used to easily determine which renderer we are using
     * @example if (board.renderer.type === 'vml') {
     *     // do something
     * }
     * @type String
     */
    this.type = '';
};

JXG.extend(JXG.AbstractRenderer.prototype, /** @lends JXG.AbstractRenderer.prototype */ {

    /* ******************************** *
     *    private methods               *
     *    should not be called from     *
     *    outside AbstractRenderer      *
     * ******************************** */

    /**
     * Update visual properties, but only if {@link JXG.AbstractRenderer#enhancedRendering} or <tt>enhanced</tt> is set to true.
     * @param {JXG.GeometryElement} element The element to update
     * @param {Object} [not={}] Select properties you don't want to be updated: <tt>{fill: true, dash: true}</tt> updates
     * everything except for fill and dash. Possible values are <tt>stroke, fill, dash, shadow, gradient</tt>.
     * @param {Boolean} [enhanced=false] If true, {@link JXG.AbstractRenderer#enhancedRendering} is assumed to be true.
     * @private
     */
    _updateVisual: function (element, not, enhanced) {
        var rgbo;
        
        if (enhanced || this.enhancedRendering) {
            not = not || {};

            if (!element.visProp.draft) {
                /*
                if (JXG.isFunction(element.visProp.visible)) {
                    if (element.visProp.visible()) {
                        this.hide(element);
                    } else {
                        this.show(element);
                    }
                } 
                */
                        
                if (!not.stroke) {
                    this.setObjectStrokeWidth(element, element.visProp.strokewidth);
                    this.setObjectStrokeColor(element, element.visProp.strokecolor, element.visProp.strokeopacity);
                }

                if (!not.fill) {
                    this.setObjectFillColor(element, element.visProp.fillcolor, element.visProp.fillopacity);
                }

                if (!not.dash) {
                    this.setDashStyle(element, element.visProp);
                }

                if (!not.shadow) {
                    this.setShadow(element);
                }

                if (!not.gradient) {
                    this.setShadow(element);
                }
            } else {
                this.setDraft(element);
            }
        }
    },


    /* ******************************** *
     *    Point drawing and updating    *
     * ******************************** */

    /**
     * Draws a point on the {@link JXG.Board}.
     * @param {JXG.Point} element Reference to a {@link JXG.Point} object that has to be drawn.
     * @see Point
     * @see JXG.Point
     * @see JXG.AbstractRenderer#updatePoint
     * @see JXG.AbstractRenderer#changePointStyle
     */
    drawPoint: function (element) {
        var prim,
            face = JXG.Point.prototype.normalizeFace.call(this, element.visProp.face);

        // determine how the point looks like
        if (face === 'o') {
            prim = 'ellipse';
        } else if (face === '[]') {
            prim = 'rect';
        } else {
            // cross/x, diamond/<>, triangleup/a/^, triangledown/v, triangleleft/<,
            // triangleright/>, plus/+,
            prim = 'path';
        }

        this.appendChildPrim(this.createPrim(prim, element.id), element.visProp.layer);
        this.appendNodesToElement(element, prim);

        // adjust visual propertys
        this._updateVisual(element, {dash: true, shadow: true}, true);

        // By now we only created the xml nodes and set some styles, in updatePoint
        // the attributes are filled with data.
        this.updatePoint(element);
    },

    /**
     * Updates visual appearance of the renderer element assigned to the given {@link JXG.Point}.
     * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that has to be updated.
     * @see Point
     * @see JXG.Point
     * @see JXG.AbstractRenderer#drawPoint
     * @see JXG.AbstractRenderer#changePointStyle
     */
    updatePoint: function (element) {
        var size = element.visProp.size,
            face = JXG.Point.prototype.normalizeFace.call(this, element.visProp.face);

        if (!isNaN(element.coords.scrCoords[2] + element.coords.scrCoords[1])) {
            this._updateVisual(element, {dash: false, shadow: false});

            // Zoom does not work for traces.
            size *= ((!element.board || !element.board.options.point.zoom) ? 1.0 : Math.sqrt(element.board.zoomX * element.board.zoomY));

            if (face === 'o') { // circle
                this.updateEllipsePrim(element.rendNode, element.coords.scrCoords[1], element.coords.scrCoords[2], size + 1, size + 1);
            } else if (face === '[]') { // rectangle
                this.updateRectPrim(element.rendNode, element.coords.scrCoords[1] - size, element.coords.scrCoords[2] - size, size * 2, size * 2);
            } else { // x, +, <>, ^, v, <, >
                this.updatePathPrim(element.rendNode, this.updatePathStringPoint(element, size, face), element.board);
            }
            this.setShadow(element);
        }
    },

    /**
     * Changes the style of a {@link JXG.Point}. This is required because the point styles differ in what
     * elements have to be drawn, e.g. if the point is marked by a "x" or a "+" two lines are drawn, if
     * it's marked by spot a circle is drawn. This method removes the old renderer element(s) and creates
     * the new one(s).
     * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that's style is changed.
     * @see Point
     * @see JXG.Point
     * @see JXG.AbstractRenderer#updatePoint
     * @see JXG.AbstractRenderer#drawPoint
     */
    changePointStyle: function (element) {
        var node = this.getElementById(element.id);

        // remove the existing point rendering node
        if (JXG.exists(node)) {
            this.remove(node);
        }

        // and make a new one
        this.drawPoint(element);
        JXG.clearVisPropOld(element);

        if (!element.visProp.visible) {
            this.hide(element);
        }

        if (element.visProp.draft) {
            this.setDraft(element);
        }
    },

    /* ******************************** *
     *           Lines                  *
     * ******************************** */

    /**
     * Draws a line on the {@link JXG.Board}.
     * @param {JXG.Line} element Reference to a line object, that has to be drawn.
     * @see Line
     * @see JXG.Line
     * @see JXG.AbstractRenderer#updateLine
     */
    drawLine: function (element) {
        this.appendChildPrim(this.createPrim('line', element.id), element.visProp.layer);
        this.appendNodesToElement(element, 'lines');
        this.updateLine(element);
    },

    /**
     * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}.
     * @param {JXG.Line} element Reference to the {@link JXG.Line} object that has to be updated.
     * @see Line
     * @see JXG.Line
     * @see JXG.AbstractRenderer#drawLine
     */
    updateLine: function (element) {
        var c1 = new JXG.Coords(JXG.COORDS_BY_USER, element.point1.coords.usrCoords, element.board),
            c2 = new JXG.Coords(JXG.COORDS_BY_USER, element.point2.coords.usrCoords, element.board),
            margin = null;

        if (element.visProp.firstarrow || element.visProp.lastarrow) {
            margin = 0;
        }
        JXG.Math.Geometry.calcStraight(element, c1, c2, margin);
        this.updateLinePrim(element.rendNode, 
                            c1.scrCoords[1], c1.scrCoords[2],
                            c2.scrCoords[1], c2.scrCoords[2], element.board);

        this.makeArrows(element);
        this._updateVisual(element, {fill: true});
    },

    /**
     * Creates a rendering node for ticks added to a line.
     * @param {JXG.Line} element A arbitrary line.
     * @see Line
     * @see Ticks
     * @see JXG.Line
     * @see JXG.Ticks
     * @see JXG.AbstractRenderer#updateTicks
     */
    drawTicks: function (element) {
        var node = this.createPrim('path', element.id);

        this.appendChildPrim(node, element.visProp.layer);
        this.appendNodesToElement(element, 'path');
    },

    /**
     * Update {@link Ticks} on a {@link JXG.Line}. This method is only a stub and has to be implemented
     * in any descendant renderer class.
     * @param {JXG.Line} element Reference of an line object, thats ticks have to be updated.
     * @param {Number} dxMaj Number of pixels a major tick counts in x direction.
     * @param {Number} dyMaj Number of pixels a major tick counts in y direction.
     * @param {Number} dxMin Number of pixels a minor tick counts in x direction.
     * @param {Number} dyMin Number of pixels a minor tick counts in y direction.
     * @see Line
     * @see Ticks
     * @see JXG.Line
     * @see JXG.Ticks
     * @see JXG.AbstractRenderer#drawTicks
     */
    updateTicks: function (element, dxMaj, dyMaj, dxMin, dyMin) { /* stub */ },

    /* **************************
     *    Curves
     * **************************/

    /**
     * Draws a {@link JXG.Curve} on the {@link JXG.Board}.
     * @param {JXG.Curve} element Reference to a graph object, that has to be plotted.
     * @see Curve
     * @see JXG.Curve
     * @see JXG.AbstractRenderer#updateCurve
     */
    drawCurve: function (element) {
        this.appendChildPrim(this.createPrim('path', element.id), element.visProp.layer);
        this.appendNodesToElement(element, 'path');
        this._updateVisual(element, {shadow: true}, true);
        this.updateCurve(element);
    },

    /**
     * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}.
     * @param {JXG.Curve} element Reference to a {@link JXG.Curve} object, that has to be updated.
     * @see Curve
     * @see JXG.Curve
     * @see JXG.AbstractRenderer#drawCurve
     */
    updateCurve: function (element) {
        this._updateVisual(element);
        if (element.visProp.handdrawing) {
            this.updatePathPrim(element.rendNode, this.updatePathStringBezierPrim(element), element.board);
        } else {
            this.updatePathPrim(element.rendNode, this.updatePathStringPrim(element), element.board);
        }
        if (element.numberPoints>1) {
            this.makeArrows(element);
        }
    },

    /* **************************
     *    Circle related stuff
     * **************************/

    /**
     * Draws a {@link JXG.Circle}
     * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object that has to be drawn.
     * @see Circle
     * @see JXG.Circle
     * @see JXG.AbstractRenderer#updateEllipse
     */
    drawEllipse: function (element) {
        this.appendChildPrim(this.createPrim('ellipse', element.id), element.visProp.layer);
        this.appendNodesToElement(element, 'ellipse');
        this.updateEllipse(element);
    },

    /**
     * Updates visual appearance of a given {@link JXG.Circle} on the {@link JXG.Board}.
     * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object, that has to be updated.
     * @see Circle
     * @see JXG.Circle
     * @see JXG.AbstractRenderer#drawEllipse
     */
    updateEllipse: function (element) {
        this._updateVisual(element);

        // Radius umrechnen:
        var radius = element.Radius();
        if (radius > 0.0 
            && Math.abs(element.center.coords.usrCoords[0])>JXG.Math.eps
            && !isNaN(radius + element.center.coords.scrCoords[1] + element.center.coords.scrCoords[2]) 
            && radius * element.board.unitX < 2000000) {
            this.updateEllipsePrim(element.rendNode, element.center.coords.scrCoords[1], element.center.coords.scrCoords[2],
                    (radius * element.board.unitX), (radius * element.board.unitY));
        } 
    },


    /* **************************
     *   Polygon related stuff
     * **************************/

    /**
     * Draws a {@link JXG.Polygon} on the {@link JXG.Board}.
     * @param {JXG.Polygon} element Reference to a Polygon object, that is to be drawn.
     * @see Polygon
     * @see JXG.Polygon
     * @see JXG.AbstractRenderer#updatePolygon
     */
    drawPolygon: function (element) {
        this.appendChildPrim(this.createPrim('polygon', element.id), element.visProp.layer);
        this.appendNodesToElement(element, 'polygon');
        this.updatePolygon(element);
    },

    /**
     * Updates properties of a {@link JXG.Polygon}'s rendering node.
     * @param {JXG.Polygon} element Reference to a {@link JXG.Polygon} object, that has to be updated.
     * @see Polygon
     * @see JXG.Polygon
     * @see JXG.AbstractRenderer#drawPolygon
     */
    updatePolygon: function (element) {
        // here originally strokecolor wasn't updated but strokewidth was
        // but if there's no strokecolor i don't see why we should update strokewidth.
        this._updateVisual(element, {stroke: true, dash: true});
        this.updatePolygonPrim(element.rendNode, element);
    },

    /* **************************
     *    Text related stuff
     * **************************/

    /**
     * Shows a small copyright notice in the top left corner of the board.
     * @param {String} str The copyright notice itself
     * @param {Number} fontsize Size of the font the copyright notice is written in
     */
    displayCopyright: function (str, fontsize) { /* stub */ },

    /**
     * An internal text is a {@link JXG.Text} element which is drawn using only
     * the given renderer but no HTML. This method is only a stub, the drawing
     * is done in the special renderers.
     * @param {JXG.Text} element Reference to a {@link JXG.Text} object
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#updateInternalText
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    drawInternalText: function (element) { /* stub */ },

    /**
     * Updates visual properties of an already existing {@link JXG.Text} element.
     * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated.
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    updateInternalText: function (element) { /* stub */ },

    /**
     * Displays a {@link JXG.Text} on the {@link JXG.Board} by putting a HTML div over it.
     * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be displayed
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateInternalText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    drawText: function (element) {
        var node, z;

        if (element.visProp.display === 'html') {
            node = this.container.ownerDocument.createElement('div');
            node.style.position = 'absolute';

            node.className = element.visProp.cssclass;
            if (this.container.style.zIndex=='') {
                z = 0;
            } else {
                z = parseInt(this.container.style.zIndex);
            }

            node.style.zIndex = z+element.board.options.layer.text; //'10';
            this.container.appendChild(node);
            node.setAttribute('id', this.container.id + '_' + element.id);
        } else {
            node = this.drawInternalText(element);
        }

        element.rendNode = node;
        element.htmlStr = '';
        this.updateText(element);
    },

    /**
     * Updates visual properties of an already existing {@link JXG.Text} element.
     * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated.
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#updateInternalText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    updateText: function (el) {
        var content = el.plaintext;

        if (el.visProp.visible) {
            this.updateTextStyle(el, false);

            if (el.visProp.display === 'html') {
                // Set the position
                if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) {
                    if (el.visProp.anchorx === 'right') {
                        el.rendNode.style.right = parseInt(el.board.canvasWidth - el.coords.scrCoords[1]) + 'px';
                    } else if (el.visProp.anchorx === 'middle') {
                        el.rendNode.style.left = parseInt(el.coords.scrCoords[1]-0.5*el.size[0]) + 'px';
                    } else {   // 'left'
                        el.rendNode.style.left = parseInt(el.coords.scrCoords[1]) + 'px';
                    }
                    
                    if (el.visProp.anchory === 'top') {
                        el.rendNode.style.top = parseInt(el.coords.scrCoords[2] + this.vOffsetText) + 'px';
                    } else if (el.visProp.anchory === 'middle') {
                        el.rendNode.style.top = parseInt(el.coords.scrCoords[2] - 0.5*el.size[1] + this.vOffsetText) + 'px';
                    } else {
                        el.rendNode.style.top = parseInt(el.coords.scrCoords[2] - el.size[1] + this.vOffsetText) + 'px';
                    }
                }
                
                // Set the content
                if (el.htmlStr !== content) {
                    el.rendNode.innerHTML = content;
                    el.htmlStr = content;
                    
                    if (el.visProp.usemathjax) {
                        // typesetting directly might not work because mathjax was not loaded completely
                        // see http://www.mathjax.org/docs/1.1/typeset.html
                        MathJax.Hub.Queue(['Typeset', MathJax.Hub, el.rendNode]);
                        //MathJax.Hub.Typeset(el.rendNode);
                    } else if (el.visProp.useasciimathml) {
                        AMprocessNode(el.rendNode, false);
                    }
                }
                this.transformImage(el, el.transformations);
            } else {
                this.updateInternalText(el);
            }
        }
    },

    /**
     * Updates font-size, color and opacity propertiey and CSS style properties of a {@link JXG.Text} node.
     * This function is also called by highlight() and nohighlight().
     * @param {JXG.Text} element Reference to the {@link JXG.Text} object, that has to be updated.
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateInternalText
     * @see JXG.AbstractRenderer#updateInternalTextStyle
     */
    updateTextStyle: function (element, doHighlight) {
        var fs, so, sc, css,
            ev = element.visProp;

        if (doHighlight) {
            sc = ev.highlightstrokecolor;
            so = ev.highlightstrokeopacity;
            css = ev.highlightcssclass;
        } else {
            sc = ev.strokecolor;
            so = ev.strokeopacity;
            css = ev.cssclass;
        }
       
        /*
         * This part is executed for all text elements except internal texts in canvas.
         */
        if (element.visProp.display === 'html' || this.type != 'canvas') {
            fs = JXG.evaluate(element.visProp.fontsize);
            if (element.visPropOld.fontsize != fs) {
                try {
                    element.rendNode.style.fontSize = fs + 'px';
                } catch (e) {
                    // IE needs special treatment.
                    element.rendNode.style.fontSize = fs;
                }
                element.visPropOld.fontsize = fs;
            }
            
            if (element.visPropOld.cssclass != css) {
                element.rendNode.className = css;
                element.visPropOld.cssclass = css;
            }
        }
        if (element.visProp.display === 'html') {
            this.setObjectStrokeColor(element, sc, so);        
        } else {
            this.updateInternalTextStyle(element, sc, so);
        }
        return this;
    },
    
    /**
     * Set color and opacity of internal texts. 
     * This method is used for Canvas and VML.
     * SVG needs its own version.
     * @private
     * @see JXG.AbstractRenderer#updateTextStyle
     * @see JXG.SVGRenderer#updateInternalTextStyle
     */
    updateInternalTextStyle: function(element, strokeColor, strokeOpacity) {
        this.setObjectStrokeColor(element, strokeColor, strokeOpacity);        
    },

    /* **************************
     *    Image related stuff
     * **************************/

    /**
     * Draws an {@link JXG.Image} on a board; This is just a template that has to be implemented by special renderers.
     * @param {JXG.Image} element Reference to the image object that is to be drawn
     * @see Image
     * @see JXG.Image
     * @see JXG.AbstractRenderer#updateImage
     */
    drawImage: function (element) { /* stub */ },

    /**
     * Updates the properties of an {@link JXG.Image} element.
     * @param {JXG.Image} element Reference to an {@link JXG.Image} object, that has to be updated.
     * @see Image
     * @see JXG.Image
     * @see JXG.AbstractRenderer#drawImage
     */
    updateImage: function (element) {
        this.updateRectPrim(element.rendNode, element.coords.scrCoords[1], element.coords.scrCoords[2] - element.size[1],
                element.size[0], element.size[1]);

        this.updateImageURL(element);
        this.transformImage(element, element.transformations);
        this._updateVisual(element, {stroke: true, dash: true}, true);
    },

    /**
     * Multiplication of transformations without updating. That means, at that point it is expected that the matrices
     * contain numbers only. First, the origin in user coords is translated to <tt>(0,0)</tt> in screen coords.
     * Then, the stretch factors are divided out. After the transformations in user coords, the  stretch factors
     * are multiplied in again, and the origin in user coords is translated back to its position.
     * This method does not have to be implemented in a new renderer.
     * @param {JXG.GeometryElement} element A JSXGraph element. We only need its board property.
     * @param {Array} transformations An array of JXG.Transformations.
     * @returns {Array} A matrix represented by a two dimensional array of numbers.
     * @see JXG.AbstractRenderer#transformImage
     */
    joinTransforms: function (element, transformations) {
        var m = [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
            ox = element.board.origin.scrCoords[1],
            oy = element.board.origin.scrCoords[2],
            ux = element.board.unitX,
            uy = element.board.unitY,
            mpre1 =  [[1,   0, 0],      // Translate to 0,0 in screen coords
                      [-ox, 1, 0], 
                      [-oy, 0, 1]],  
            mpre2 =  [[1, 0,     0],    // Scale
                      [0, 1/ux,  0], 
                      [0, 0, -1/uy]],
            mpost2 = [[1, 0,   0],      // Scale back
                      [0, ux,  0], 
                      [0, 0, -uy]],
            mpost1 = [[1,  0, 0],       // Translate back
                      [ox, 1, 0], 
                      [oy, 0, 1]],
            i, len = transformations.length;

        for (i = 0; i < len; i++) {
            m = JXG.Math.matMatMult(mpre1, m);
            m = JXG.Math.matMatMult(mpre2, m);
            m = JXG.Math.matMatMult(transformations[i].matrix, m);
            m = JXG.Math.matMatMult(mpost2, m);
            m = JXG.Math.matMatMult(mpost1, m);
        }
        return m;
    },

    /**
     * Applies transformations on images and text elements. This method is just a stub and has to be implemented in all
     * descendant classes where text and image transformations are to be supported.
     * @param {JXG.Image|JXG.Text} element A {@link JXG.Image} or {@link JXG.Text} object.
     * @param {Array} transformations An array of {@link JXG.Transformation} objects. This is usually the transformations property
     * of the given element <tt>el</tt>.
     */
    transformImage: function (element, transformations) { /* stub */ },

    /**
     * If the URL of the image is provided by a function the URL has to be updated during updateImage()
     * @param {JXG.Image} element Reference to an image object.
     * @see JXG.AbstractRenderer#updateImage
     */
    updateImageURL: function (element) { /* stub */ },

    /**
     * Updates CSS style properties of a {@link JXG.Image} node.
     * In SVGRenderer opacity is the only available style element.
     * This function is called by highlight() and nohighlight().
     * This function works for VML. 
     * It does not work for Canvas.
     * SVGRenderer overwrites this method.
     * @param {JXG.Text} element Reference to the {@link JXG.Image} object, that has to be updated.
     * @see Image
     * @see JXG.Image
     * @see JXG.AbstractRenderer#highlight
     * @see JXG.AbstractRenderer#nohighlight
     */
    updateImageStyle: function(element, doHighlight) { 
        var css = (doHighlight) ? el.visProp.highlightcssclass : el.visProp.cssclass;
        
        element.rendNode.className = css;
    },


    /* **************************
     * Render primitive objects
     * **************************/

    /**
     * Appends a node to a specific layer level. This is just an abstract method and has to be implemented
     * in all renderers that want to use the <tt>createPrim</tt> model to draw.
     * @param {Node} node A DOM tree node.
     * @param {Number} level The layer the node is attached to. This is the index of the layer in
     * {@link JXG.SVGRenderer#layer} or the <tt>z-index</tt> style property of the node in VMLRenderer.
     */
    appendChildPrim: function (node, level) { /* stub */ },

    /**
     * Stores the rendering nodes. This is an abstract method which has to be implemented in all renderers that use
     * the <tt>createPrim</tt> method.
     * @param {JXG.GeometryElement} element A JSXGraph element.
     * @param {String} type The XML node name. Only used in VMLRenderer.
     */
    appendNodesToElement: function (element, type) { /* stub */ },

    /**
     * Creates a node of a given type with a given id.
     * @param {String} type The type of the node to create.
     * @param {String} id Set the id attribute to this.
     * @returns {Node} Reference to the created node.
     */
    createPrim: function (type, id) {
        /* stub */
        return null;
    },

    /**
     * Removes an element node. Just a stub.
     * @param {Node} node The node to remove.
     */
    remove: function (node) { /* stub */ },    

    /**
     * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented
     * in any descendant renderer.
     * @param {JXG.GeometryElement} element The element the arrows are to be attached to.
     */
    makeArrows: function(element) { /* stub */ },

    /**
     * Updates an ellipse node primitive. This is an abstract method which has to be implemented in all renderers
     * that use the <tt>createPrim</tt> method.
     * @param {Node} node Reference to the node.
     * @param {Number} x Centre X coordinate
     * @param {Number} y Centre Y coordinate
     * @param {Number} rx The x-axis radius.
     * @param {Number} ry The y-axis radius.
     */
    updateEllipsePrim: function(node, x, y, rx, ry) { /* stub */ },

    /**
     * Refreshes a line node. This is an abstract method which has to be implemented in all renderers that use
     * the <tt>createPrim</tt> method.
     * @param {Node} node The node to be refreshed.
     * @param {Number} p1x The first point's x coordinate.
     * @param {Number} p1y The first point's y coordinate.
     * @param {Number} p2x The second point's x coordinate.
     * @param {Number} p2y The second point's y coordinate.
     * @param {JXG.Board} board
     */
    updateLinePrim: function(node, p1x, p1y, p2x, p2y, board) { /* stub */ },

    /**
     * Updates a path element. This is an abstract method which has to be implemented in all renderers that use
     * the <tt>createPrim</tt> method.
     * @param {Node} node The path node.
     * @param {String} pathString A string formatted like e.g. <em>'M 1,2 L 3,1 L5,5'</em>. The format of the string
     * depends on the rendering engine.
     * @param {JXG.Board} board Reference to the element's board.
     */
    updatePathPrim: function (node, pathString, board) { /* stub */ },

    /**
     * Builds a path data string to draw a point with a face other than <em>rect</em> and <em>circle</em>. Since
     * the format of such a string usually depends on the renderer this method
     * is only an abstract method. Therefore, it has to be implemented in the descendant renderer itself unless
     * the renderer does not use the createPrim interface but the draw* interfaces to paint.
     * @param {JXG.Point} element The point element
     * @param {Number} size A positive number describing the size. Usually the half of the width and height of
     * the drawn point.
     * @param {String} type A string describing the point's face. This method only accepts the shortcut version of
     * each possible face: <tt>x, +, <>, ^, v, >, <
     */
    updatePathStringPoint: function (element, size, type) { /* stub */ },

    /**
     * Builds a path data string from a {@link JXG.Curve} element. Since the path data strings heavily depend on the
     * underlying rendering technique this method is just a stub. Although such a path string is of no use for the
     * CanvasRenderer, this method is used there to draw a path directly.
     * @param element
     */
    updatePathStringPrim: function (element) { /* stub */ },

    /**
     * Builds a path data string from a {@link JXG.Curve} element such that the curve looks like
     * hand drawn.
     * Since the path data strings heavily depend on the
     * underlying rendering technique this method is just a stub. Although such a path string is of no use for the
     * CanvasRenderer, this method is used there to draw a path directly.
     * @param element
     */
    updatePathStringBezierPrim: function (element) { /* stub */ },

    
    /**
     * Update a polygon primitive.
     * @param {Node} node
     * @param {JXG.Polygon} element A JSXGraph element of type {@link JXG.Polygon}
     */
    updatePolygonPrim: function (node, element) { /* stub */ },

    /**
     * Update a rectangle primitive. This is used only for points with face of type 'rect'.
     * @param {Node} node The node yearning to be updated.
     * @param {Number} x x coordinate of the top left vertex.
     * @param {Number} y y coordinate of the top left vertex.
     * @param {Number} w Width of the rectangle.
     * @param {Number} h The rectangle's height.
     */
    updateRectPrim: function(node, x, y, w, h) { /* stub */ },

    /* **************************
     *  Set Attributes
     * **************************/

    /**
     * Sets a node's attribute.
     * @param {Node} node The node that is to be updated.
     * @param {String} key Name of the attribute.
     * @param {String} val New value for the attribute.
     */
    setPropertyPrim: function (node, key, val) { /* stub */ },

    /**
     * Shows a hidden element on the canvas; Only a stub, requires implementation in the derived renderer.
     * @param {JXG.GeometryElement} element Reference to the object that has to appear.
     * @see JXG.AbstractRenderer#hide
     */
    show: function (element) { /* stub */ },

    /**
     * Hides an element on the canvas; Only a stub, requires implementation in the derived renderer.
     * @param {JXG.GeometryElement} element Reference to the geometry element that has to disappear.
     * @see JXG.AbstractRenderer#show
     */
    hide: function (element) { /* stub */ },

    /**
     * Sets the buffering as recommended by SVGWG. Until now only Opera supports this and will be ignored by
     * other browsers. Although this feature is only supported by SVG we have this method in {@link JXG.AbstractRenderer}
     * because it is called from outside the renderer.
     * @param {Node} node The SVG DOM Node which buffering type to update.
     * @param {String} type Either 'auto', 'dynamic', or 'static'. For an explanation see
     *   {@link http://www.w3.org/TR/SVGTiny12/painting.html#BufferedRenderingProperty}.
     */
    setBuffering: function (node, type) { /* stub */ },

    /**
     * Sets an element's dash style.
     * @param {JXG.GeometryElement} element An JSXGraph element.
     */
    setDashStyle: function (element) { /* stub */ },

    /**
     * Puts an object into draft mode, i.e. it's visual appearance will be changed. For GEONE<sub>x</sub>T backwards compatibility.
     * @param {JXG.GeometryElement} element Reference of the object that is in draft mode.
     */
    setDraft: function (element) {
        if (!element.visProp.draft) {
            return;
        }
        var draftColor = element.board.options.elements.draft.color,
            draftOpacity = element.board.options.elements.draft.opacity;

        if (element.type === JXG.OBJECT_TYPE_POLYGON) {
            this.setObjectFillColor(element, draftColor, draftOpacity);
        }
        else {
            if (element.elementClass === JXG.OBJECT_CLASS_POINT) {
                this.setObjectFillColor(element, draftColor, draftOpacity);
            }
            else {
                this.setObjectFillColor(element, 'none', 0);
            }
            this.setObjectStrokeColor(element, draftColor, draftOpacity);
            this.setObjectStrokeWidth(element, element.board.options.elements.draft.strokeWidth);
        }
    },

    /**
     * Puts an object from draft mode back into normal mode.
     * @param {JXG.GeometryElement} element Reference of the object that no longer is in draft mode.
     */
    removeDraft: function (element) {
        if (element.type === JXG.OBJECT_TYPE_POLYGON) {
            this.setObjectFillColor(element, element.visProp.fillcolor, element.visProp.fillopacity);
        }
        else {
            if (element.type === JXG.OBJECT_CLASS_POINT) {
                this.setObjectFillColor(element, element.visProp.fillcolor, element.visProp.fillopacity);
            }
            this.setObjectStrokeColor(element, element.visProp.strokecolor, element.visProp.strokeopacity);
            this.setObjectStrokeWidth(element, element.visProp.strokewidth);
        }
    },

    /**
     * Sets up nodes for rendering a gradient fill.
     * @param element
     */
    setGradient: function (element) { /* stub */ },

    /**
     * Updates the gradient fill.
     * @param {JXG.GeometryElement} element An JSXGraph element with an area that can be filled.
     */
    updateGradient: function (element) { /* stub */ },

    /**
     * Sets an objects fill color.
     * @param {JXG.GeometryElement} element Reference of the object that wants a new fill color.
     * @param {String} color Color in a HTML/CSS compatible format. If you don't want any fill color at all, choose 'none'.
     * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.
     */
    setObjectFillColor: function (element, color, opacity) { /* stub */ },

    /**
     * Changes an objects stroke color to the given color.
     * @param {JXG.GeometryElement} element Reference of the {@link JXG.GeometryElement} that gets a new stroke color.
     * @param {String} color Color value in a HTML compatible format, e.g. <strong>#00ff00</strong> or <strong>green</strong> for green.
     * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.
     */
    setObjectStrokeColor: function (element, color, opacity) { /* stub */ },

    /**
     * Sets an element's stroke width.
     * @param {JXG.GeometryElement} element Reference to the geometry element.
     * @param {Number} width The new stroke width to be assigned to the element.
     */
    setObjectStrokeWidth: function (element, width) { /* stub */ },
    
    /**
     * Sets the shadow properties to a geometry element. This method is only a stub, it is implemented in the actual renderers.
     * @param {JXG.GeometryElement} element Reference to a geometry object, that should get a shadow
     */
    setShadow: function (element) { /* stub */ },

    /**
     * Highlights an object, i.e. changes the current colors of the object to its highlighting colors
     * @param {JXG.GeometryElement} element Reference of the object that will be highlighted.
     * @returns {JXG.AbstractRenderer} Reference to the renderer
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    highlight: function (element) {
        var i, ev = element.visProp;

        if (!ev.draft) {
            /*
               // Why did we have this? A.W.
            if (element.elementClass === JXG.OBJECT_CLASS_POINT) {
                this.setObjectStrokeColor(element, ev.highlightstrokecolor, ev.highlightstrokeopacity);
                this.setObjectFillColor(element, ev.highlightstrokecolor, ev.highlightstrokeopacity);
            } else 
            */
            if (element.type === JXG.OBJECT_TYPE_POLYGON) {
                this.setObjectFillColor(element, ev.highlightfillcolor, ev.highlightfillopacity);
                for (i = 0; i < element.borders.length; i++) {
                    this.setObjectStrokeColor(element.borders[i], element.borders[i].visProp.highlightstrokecolor, element.borders[i].visProp.highlightstrokeopacity);
                }
            } else {
                if (element.type === JXG.OBJECT_TYPE_TEXT) {
                    this.updateTextStyle(element, true);
                } else if (element.type === JXG.OBJECT_TYPE_IMAGE) {
                    this.updateImageStyle(element, true);
                    //element.rendNode.className = 'JXGimageHighlight';
                    //element.rendNode.setAttributeNS(null, 'class', 'JXGimageHighlight');
                } else {
                    this.setObjectStrokeColor(element, ev.highlightstrokecolor, ev.highlightstrokeopacity);
                    this.setObjectFillColor(element, ev.highlightfillcolor, ev.highlightfillopacity);
                }
            }
            if (ev.highlightstrokewidth) {
                this.setObjectStrokeWidth(element, Math.max(ev.highlightstrokewidth, ev.strokewidth));
            }
        }

        return this;
    },

    /**
     * Uses the normal colors of an object, i.e. the opposite of {@link JXG.AbstractRenderer#highlight}.
     * @param {JXG.GeometryElement} element Reference of the object that will get its normal colors.
     * @returns {JXG.AbstractRenderer} Reference to the renderer
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    noHighlight: function (element) {
        var i, ev = element.visProp;

        if (!element.visProp.draft) {
            /* 
               // Why did we have this? A.W.
              if (element.elementClass === JXG.OBJECT_CLASS_POINT) {
                this.setObjectStrokeColor(element, ev.strokecolor, ev.strokeopacity);
                this.setObjectFillColor(element, ev.strokecolor, ev.strokeopacity);
            } else 
            */
            if (element.type === JXG.OBJECT_TYPE_POLYGON) {
                this.setObjectFillColor(element, ev.fillcolor, ev.fillopacity);
                for (i = 0; i < element.borders.length; i++) {
                    this.setObjectStrokeColor(element.borders[i], element.borders[i].visProp.strokecolor, element.borders[i].visProp.strokeopacity);
                }
            } else {
                if (element.type === JXG.OBJECT_TYPE_TEXT) {
                    this.updateTextStyle(element, false);
                } else if (element.type === JXG.OBJECT_TYPE_IMAGE) {
                    this.updateImageStyle(element, false);
                    //element.rendNode.setAttributeNS(null, 'class', 'JXGimage');
                } else {
                    this.setObjectStrokeColor(element, ev.strokecolor, ev.strokeopacity);
                    this.setObjectFillColor(element, ev.fillcolor, ev.fillopacity);
                }
            }
            this.setObjectStrokeWidth(element, ev.strokewidth);
        }

        return this;
    },

    /* **************************
     * renderer control
     * **************************/

    /**
     * Stop redraw. This method is called before every update, so a non-vector-graphics based renderer
     * can use this method to delete the contents of the drawing panel. This is an abstract method every
     * descendant renderer should implement, if appropriate.
     * @see JXG.AbstractRenderer#unsuspendRedraw
     */
    suspendRedraw: function () { /* stub */ },

    /**
     * Restart redraw. This method is called after updating all the rendering node attributes.
     * @see JXG.AbstractRenderer#suspendRedraw
     */
    unsuspendRedraw: function () { /* stub */ },

    /**
     * The tiny zoom bar shown on the bottom of a board (if showNavigation on board creation is true).
     * @param {JXG.Board} board Reference to a JSXGraph board.
     */
    drawZoomBar: function (board) {
        var doc,
            node,
            createButton = function (label, handler) {
                var button;

                button = doc.createElement('span');
                node.appendChild(button);
                button.appendChild(document.createTextNode(label));
                /* button.innerHTML = label; */ // Does not work in XHTML
                JXG.addEvent(button, 'click', handler, board);
            };

        doc = board.containerObj.ownerDocument;
        node = doc.createElement('div');

        node.setAttribute('id', board.containerObj.id + '_navigationbar');

        node.style.color = board.options.navbar.strokeColor;
        node.style.backgroundColor = board.options.navbar.fillColor;
        node.style.padding = board.options.navbar.padding;
        node.style.position = board.options.navbar.position;
        node.style.fontSize = board.options.navbar.fontSize;
        node.style.cursor = board.options.navbar.cursor;
        node.style.zIndex = board.options.navbar.zIndex;
        board.containerObj.appendChild(node);
        node.style.right = board.options.navbar.right;
        node.style.bottom = board.options.navbar.bottom;

        // For XHTML we need unicode instead of HTML entities
        createButton('\u00A0\u2013\u00A0', board.zoomOut);
        createButton('\u00A0o\u00A0', board.zoom100);
        createButton('\u00A0+\u00A0', board.zoomIn);
        createButton('\u00A0\u2190\u00A0', board.clickLeftArrow);
        createButton('\u00A0\u2193\u00A0', board.clickUpArrow);
        createButton('\u00A0\u2191\u00A0', board.clickDownArrow);
        createButton('\u00A0\u2192\u00A0', board.clickRightArrow);
    },

    /**
     * Wrapper for getElementById for maybe other renderers which elements are not directly accessible by DOM methods like document.getElementById().
     * @param {String} id Unique identifier for element.
     * @returns {Object} Reference to a JavaScript object. In case of SVG/VMLRenderer it's a reference to a SVG/VML node.
     */
    getElementById: function (id) {
        return document.getElementById(this.container.id + '_' + id);
    },

    /**
     * Resizes the rendering element
     * @param {Number} w New width
     * @param {Number} h New height
     */
    resize: function (w, h) { /* stub */}

});


/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.

*/

/*jshint bitwise: false, curly: true, debug: false, eqeqeq: true, devel: false, evil: false,
  forin: false, immed: true, laxbreak: false, newcap: false, noarg: true, nonew: true, onevar: true,
   undef: true, white: true, sub: false*/
/*global JXG: true, AMprocessNode: true, MathJax: true, document: true */

/**
 * @fileoverview JSXGraph can use various technologies to render the contents of a construction, e.g.
 * SVG, VML, and HTML5 Canvas. To accomplish this, The rendering and the logic and control mechanisms
 * are completely separated from each other. Every rendering technology has it's own class, called
 * Renderer, e.g. SVGRenderer for SVG, the same for VML and Canvas. The common base for all available
 * renderers is the class AbstractRenderer.
 */

/**
 * @class JXG.AbstractRenderer
 */
JXG.NoRenderer = function () {
    /**
     * If this property is set to <tt>true</tt> the visual properties of the elements are updated
     * on every update. Visual properties means: All the stuff stored in the
     * {@link JXG.GeometryElement#visProp} property won't be set if enhancedRendering is <tt>false</tt>
     * @type Boolean
     * @default true
     */
    this.enhancedRendering = false;

    /**
     * This is used to easily determine which renderer we are using
     * @example if (board.renderer.type === 'vml') {
     *     // do something
     * }
     * @type String
     */
    this.type = 'no';
};

JXG.extend(JXG.NoRenderer.prototype, /** @lends JXG.AbstractRenderer.prototype */ {
    /* ******************************** *
     *    Point drawing and updating    *
     * ******************************** */

    /**
     * Draws a point on the {@link JXG.Board}.
     * @param {JXG.Point} element Reference to a {@link JXG.Point} object that has to be drawn.
     * @see Point
     * @see JXG.Point
     * @see JXG.AbstractRenderer#updatePoint
     * @see JXG.AbstractRenderer#changePointStyle
     */
    drawPoint: function (element) {},

    /**
     * Updates visual appearance of the renderer element assigned to the given {@link JXG.Point}.
     * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that has to be updated.
     * @see Point
     * @see JXG.Point
     * @see JXG.AbstractRenderer#drawPoint
     * @see JXG.AbstractRenderer#changePointStyle
     */
    updatePoint: function (element) { },

    /**
     * Changes the style of a {@link JXG.Point}. This is required because the point styles differ in what
     * elements have to be drawn, e.g. if the point is marked by a "x" or a "+" two lines are drawn, if
     * it's marked by spot a circle is drawn. This method removes the old renderer element(s) and creates
     * the new one(s).
     * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that's style is changed.
     * @see Point
     * @see JXG.Point
     * @see JXG.AbstractRenderer#updatePoint
     * @see JXG.AbstractRenderer#drawPoint
     */
    changePointStyle: function (element) { },

    /* ******************************** *
     *           Lines                  *
     * ******************************** */

    /**
     * Draws a line on the {@link JXG.Board}.
     * @param {JXG.Line} element Reference to a line object, that has to be drawn.
     * @see Line
     * @see JXG.Line
     * @see JXG.AbstractRenderer#updateLine
     */
    drawLine: function (element) { },

    /**
     * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}.
     * @param {JXG.Line} element Reference to the {@link JXG.Line} object that has to be updated.
     * @see Line
     * @see JXG.Line
     * @see JXG.AbstractRenderer#drawLine
     */
    updateLine: function (element) { },

    /**
     * Creates a rendering node for ticks added to a line.
     * @param {JXG.Line} element A arbitrary line.
     * @see Line
     * @see Ticks
     * @see JXG.Line
     * @see JXG.Ticks
     * @see JXG.AbstractRenderer#updateTicks
     */
    drawTicks: function (element) { },

    /**
     * Update {@link Ticks} on a {@link JXG.Line}. This method is only a stub and has to be implemented
     * in any descendant renderer class.
     * @param {JXG.Line} element Reference of an line object, thats ticks have to be updated.
     * @param {Number} dxMaj Number of pixels a major tick counts in x direction.
     * @param {Number} dyMaj Number of pixels a major tick counts in y direction.
     * @param {Number} dxMin Number of pixels a minor tick counts in x direction.
     * @param {Number} dyMin Number of pixels a minor tick counts in y direction.
     * @see Line
     * @see Ticks
     * @see JXG.Line
     * @see JXG.Ticks
     * @see JXG.AbstractRenderer#drawTicks
     */
    updateTicks: function (element, dxMaj, dyMaj, dxMin, dyMin) { /* stub */ },

    /* **************************
     *    Curves
     * **************************/

    /**
     * Draws a {@link JXG.Curve} on the {@link JXG.Board}.
     * @param {JXG.Curve} element Reference to a graph object, that has to be plotted.
     * @see Curve
     * @see JXG.Curve
     * @see JXG.AbstractRenderer#updateCurve
     */
    drawCurve: function (element) { },

    /**
     * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}.
     * @param {JXG.Curve} element Reference to a {@link JXG.Curve} object, that has to be updated.
     * @see Curve
     * @see JXG.Curve
     * @see JXG.AbstractRenderer#drawCurve
     */
    updateCurve: function (element) { },

    /* **************************
     *    Circle related stuff
     * **************************/

    /**
     * Draws a {@link JXG.Circle}
     * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object that has to be drawn.
     * @see Circle
     * @see JXG.Circle
     * @see JXG.AbstractRenderer#updateEllipse
     */
    drawEllipse: function (element) { },

    /**
     * Updates visual appearance of a given {@link JXG.Circle} on the {@link JXG.Board}.
     * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object, that has to be updated.
     * @see Circle
     * @see JXG.Circle
     * @see JXG.AbstractRenderer#drawEllipse
     */
    updateEllipse: function (element) { },


    /* **************************
     *   Polygon related stuff
     * **************************/

    /**
     * Draws a {@link JXG.Polygon} on the {@link JXG.Board}.
     * @param {JXG.Polygon} element Reference to a Polygon object, that is to be drawn.
     * @see Polygon
     * @see JXG.Polygon
     * @see JXG.AbstractRenderer#updatePolygon
     */
    drawPolygon: function (element) { },

    /**
     * Updates properties of a {@link JXG.Polygon}'s rendering node.
     * @param {JXG.Polygon} element Reference to a {@link JXG.Polygon} object, that has to be updated.
     * @see Polygon
     * @see JXG.Polygon
     * @see JXG.AbstractRenderer#drawPolygon
     */
    updatePolygon: function (element) { },

    /* **************************
     *    Text related stuff
     * **************************/

    /**
     * Shows a small copyright notice in the top left corner of the board.
     * @param {String} str The copyright notice itself
     * @param {Number} fontsize Size of the font the copyright notice is written in
     */
    displayCopyright: function (str, fontsize) { /* stub */ },

    /**
     * An internal text is a {@link JXG.Text} element which is drawn using only
     * the given renderer but no HTML. This method is only a stub, the drawing
     * is done in the special renderers.
     * @param {JXG.Text} element Reference to a {@link JXG.Text} object
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#updateInternalText
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    drawInternalText: function (element) { /* stub */ },

    /**
     * Updates visual properties of an already existing {@link JXG.Text} element.
     * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated.
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    updateInternalText: function (element) { /* stub */ },

    /**
     * Displays a {@link JXG.Text} on the {@link JXG.Board} by putting a HTML div over it.
     * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be displayed
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateInternalText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    drawText: function (element) { },

    /**
     * Updates visual properties of an already existing {@link JXG.Text} element.
     * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated.
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#updateInternalText
     * @see JXG.AbstractRenderer#updateTextStyle
     */
    updateText: function (element) { },

    /**
     * Updates CSS style properties of a {@link JXG.Text} node.
     * @param {JXG.Text} element Reference to the {@link JXG.Text} object, that has to be updated.
     * @see Text
     * @see JXG.Text
     * @see JXG.AbstractRenderer#drawText
     * @see JXG.AbstractRenderer#drawInternalText
     * @see JXG.AbstractRenderer#updateText
     * @see JXG.AbstractRenderer#updateInternalText
     */
    updateTextStyle: function (element, doHighlight) { },

     /**
     * Set color and opacity of internal texts. 
     * SVG needs its own version.
     * @private
     * @see JXG.AbstractRenderer#updateTextStyle
     * @see JXG.AbstractRenderer#updateInternalTextStyle
     */
    updateInternalTextStyle: function(element, strokeColor, strokeOpacity) { /* stub */ },

    /* **************************
     *    Image related stuff
     * **************************/

    /**
     * Draws an {@link JXG.Image} on a board; This is just a template that has to be implemented by special renderers.
     * @param {JXG.Image} element Reference to the image object that is to be drawn
     * @see Image
     * @see JXG.Image
     * @see JXG.AbstractRenderer#updateImage
     */
    drawImage: function (element) { /* stub */ },

    /**
     * Updates the properties of an {@link JXG.Image} element.
     * @param {JXG.Image} element Reference to an {@link JXG.Image} object, that has to be updated.
     * @see Image
     * @see JXG.Image
     * @see JXG.AbstractRenderer#drawImage
     */
    updateImage: function (element) { },

    /**
     * Applies transformations on images and text elements. This method is just a stub and has to be implemented in all
     * descendant classes where text and image transformations are to be supported.
     * @param {JXG.Image|JXG.Text} element A {@link JXG.Image} or {@link JXG.Text} object.
     * @param {Array} transformations An array of {@link JXG.Transformation} objects. This is usually the transformations property
     * of the given element <tt>el</tt>.
     */
    transformImage: function (element, transformations) { /* stub */ },

    /**
     * If the URL of the image is provided by a function the URL has to be updated during updateImage()
     * @param {JXG.Image} element Reference to an image object.
     * @see JXG.AbstractRenderer#updateImage
     */
    updateImageURL: function (element) { /* stub */ },

    /* **************************
     * Render primitive objects
     * **************************/

    /**
     * Appends a node to a specific layer level. This is just an abstract method and has to be implemented
     * in all renderers that want to use the <tt>createPrim</tt> model to draw.
     * @param {Node} node A DOM tree node.
     * @param {Number} level The layer the node is attached to. This is the index of the layer in
     * {@link JXG.SVGRenderer#layer} or the <tt>z-index</tt> style property of the node in VMLRenderer.
     */
    appendChildPrim: function (node, level) { /* stub */ },

    /**
     * Stores the rendering nodes. This is an abstract method which has to be implemented in all renderers that use
     * the <tt>createPrim</tt> method.
     * @param {JXG.GeometryElement} element A JSXGraph element.
     * @param {String} type The XML node name. Only used in VMLRenderer.
     */
    appendNodesToElement: function (element, type) { /* stub */ },

    /**
     * Creates a node of a given type with a given id.
     * @param {String} type The type of the node to create.
     * @param {String} id Set the id attribute to this.
     * @returns {Node} Reference to the created node.
     */
    createPrim: function (type, id) {
        /* stub */
        return null;
    },

    /**
     * Removes an element node. Just a stub.
     * @param {Node} node The node to remove.
     */
    remove: function (node) { /* stub */ },    

    /**
     * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented
     * in any descendant renderer.
     * @param {JXG.GeometryElement} element The element the arrows are to be attached to.
     */
    makeArrows: function(element) { /* stub */ },

    /**
     * Updates an ellipse node primitive. This is an abstract method which has to be implemented in all renderers
     * that use the <tt>createPrim</tt> method.
     * @param {Node} node Reference to the node.
     * @param {Number} x Centre X coordinate
     * @param {Number} y Centre Y coordinate
     * @param {Number} rx The x-axis radius.
     * @param {Number} ry The y-axis radius.
     */
    updateEllipsePrim: function(node, x, y, rx, ry) { /* stub */ },

    /**
     * Refreshes a line node. This is an abstract method which has to be implemented in all renderers that use
     * the <tt>createPrim</tt> method.
     * @param {Node} node The node to be refreshed.
     * @param {Number} p1x The first point's x coordinate.
     * @param {Number} p1y The first point's y coordinate.
     * @param {Number} p2x The second point's x coordinate.
     * @param {Number} p2y The second point's y coordinate.
     * @param {JXG.Board} board
     */
    updateLinePrim: function(node, p1x, p1y, p2x, p2y, board) { /* stub */ },

    /**
     * Updates a path element. This is an abstract method which has to be implemented in all renderers that use
     * the <tt>createPrim</tt> method.
     * @param {Node} node The path node.
     * @param {String} pathString A string formatted like e.g. <em>'M 1,2 L 3,1 L5,5'</em>. The format of the string
     * depends on the rendering engine.
     * @param {JXG.Board} board Reference to the element's board.
     */
    updatePathPrim: function (node, pathString, board) { /* stub */ },

    /**
     * Builds a path data string to draw a point with a face other than <em>rect</em> and <em>circle</em>. Since
     * the format of such a string usually depends on the renderer this method
     * is only an abstract method. Therefore, it has to be implemented in the descendant renderer itself unless
     * the renderer does not use the createPrim interface but the draw* interfaces to paint.
     * @param {JXG.Point} element The point element
     * @param {Number} size A positive number describing the size. Usually the half of the width and height of
     * the drawn point.
     * @param {String} type A string describing the point's face. This method only accepts the shortcut version of
     * each possible face: <tt>x, +, <>, ^, v, >, <
     */
    updatePathStringPoint: function (element, size, type) { /* stub */ },

    /**
     * Builds a path data string from a {@link JXG.Curve} element. Since the path data strings heavily depend on the
     * underlying rendering technique this method is just a stub. Although such a path string is of no use for the
     * CanvasRenderer, this method is used there to draw a path directly.
     * @param element
     */
    updatePathStringPrim: function (element) { /* stub */ },

    /**
     * Builds a path data string from a {@link JXG.Curve} element such that the curve looks like
     * hand drawn.
     * Since the path data strings heavily depend on the
     * underlying rendering technique this method is just a stub. Although such a path string is of no use for the
     * CanvasRenderer, this method is used there to draw a path directly.
     * @param element
     */
    updatePathStringBezierPrim: function (element) { /* stub */ },

    
    /**
     * Update a polygon primitive.
     * @param {Node} node
     * @param {JXG.Polygon} element A JSXGraph element of type {@link JXG.Polygon}
     */
    updatePolygonPrim: function (node, element) { /* stub */ },

    /**
     * Update a rectangle primitive. This is used only for points with face of type 'rect'.
     * @param {Node} node The node yearning to be updated.
     * @param {Number} x x coordinate of the top left vertex.
     * @param {Number} y y coordinate of the top left vertex.
     * @param {Number} w Width of the rectangle.
     * @param {Number} h The rectangle's height.
     */
    updateRectPrim: function(node, x, y, w, h) { /* stub */ },

    /* **************************
     *  Set Attributes
     * **************************/

    /**
     * Sets a node's attribute.
     * @param {Node} node The node that is to be updated.
     * @param {String} key Name of the attribute.
     * @param {String} val New value for the attribute.
     */
    setPropertyPrim: function (node, key, val) { /* stub */ },

    /**
     * Shows a hidden element on the canvas; Only a stub, requires implementation in the derived renderer.
     * @param {JXG.GeometryElement} element Reference to the object that has to appear.
     * @see JXG.AbstractRenderer#hide
     */
    show: function (element) { /* stub */ },

    /**
     * Hides an element on the canvas; Only a stub, requires implementation in the derived renderer.
     * @param {JXG.GeometryElement} element Reference to the geometry element that has to disappear.
     * @see JXG.AbstractRenderer#show
     */
    hide: function (element) { /* stub */ },

    /**
     * Sets the buffering as recommended by SVGWG. Until now only Opera supports this and will be ignored by
     * other browsers. Although this feature is only supported by SVG we have this method in {@link JXG.AbstractRenderer}
     * because it is called from outside the renderer.
     * @param {Node} node The SVG DOM Node which buffering type to update.
     * @param {String} type Either 'auto', 'dynamic', or 'static'. For an explanation see
     *   {@link http://www.w3.org/TR/SVGTiny12/painting.html#BufferedRenderingProperty}.
     */
    setBuffering: function (node, type) { /* stub */ },

    /**
     * Sets an element's dash style.
     * @param {JXG.GeometryElement} element An JSXGraph element.
     */
    setDashStyle: function (element) { /* stub */ },

    /**
     * Puts an object into draft mode, i.e. it's visual appearance will be changed. For GEONE<sub>x</sub>T backwards compatibility.
     * @param {JXG.GeometryElement} element Reference of the object that is in draft mode.
     */
    setDraft: function (element) { },

    /**
     * Puts an object from draft mode back into normal mode.
     * @param {JXG.GeometryElement} element Reference of the object that no longer is in draft mode.
     */
    removeDraft: function (element) { },

    /**
     * Sets up nodes for rendering a gradient fill.
     * @param element
     */
    setGradient: function (element) { /* stub */ },

    /**
     * Updates the gradient fill.
     * @param {JXG.GeometryElement} element An JSXGraph element with an area that can be filled.
     */
    updateGradient: function (element) { /* stub */ },

    /**
     * Sets an objects fill color.
     * @param {JXG.GeometryElement} element Reference of the object that wants a new fill color.
     * @param {String} color Color in a HTML/CSS compatible format. If you don't want any fill color at all, choose 'none'.
     * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.
     */
    setObjectFillColor: function (element, color, opacity) { /* stub */ },

    /**
     * Changes an objects stroke color to the given color.
     * @param {JXG.GeometryElement} element Reference of the {@link JXG.GeometryElement} that gets a new stroke color.
     * @param {String} color Color value in a HTML compatible format, e.g. <strong>#00ff00</strong> or <strong>green</strong> for green.
     * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.
     */
    setObjectStrokeColor: function (element, color, opacity) { /* stub */ },

    /**
     * Sets an element's stroke width.
     * @param {JXG.GeometryElement} element Reference to the geometry element.
     * @param {Number} width The new stroke width to be assigned to the element.
     */
    setObjectStrokeWidth: function (element, width) { /* stub */ },
    
    /**
     * Sets the shadow properties to a geometry element. This method is only a stub, it is implemented in the actual renderers.
     * @param {JXG.GeometryElement} element Reference to a geometry object, that should get a shadow
     */
    setShadow: function (element) { /* stub */ },

    /**
     * Highlights an object, i.e. changes the current colors of the object to its highlighting colors
     * @param {JXG.GeometryElement} element Reference of the object that will be highlighted.
     * @returns {JXG.AbstractRenderer} Reference to the renderer
     */
    highlight: function (element) { },

    /**
     * Uses the normal colors of an object, i.e. the opposite of {@link JXG.AbstractRenderer#highlight}.
     * @param {JXG.GeometryElement} element Reference of the object that will get its normal colors.
     * @returns {JXG.AbstractRenderer} Reference to the renderer
     */
    noHighlight: function (element) { },


    /* **************************
     * renderer control
     * **************************/

    /**
     * Stop redraw. This method is called before every update, so a non-vector-graphics based renderer
     * can use this method to delete the contents of the drawing panel. This is an abstract method every
     * descendant renderer should implement, if appropriate.
     * @see JXG.AbstractRenderer#unsuspendRedraw
     */
    suspendRedraw: function () { /* stub */ },

    /**
     * Restart redraw. This method is called after updating all the rendering node attributes.
     * @see JXG.AbstractRenderer#suspendRedraw
     */
    unsuspendRedraw: function () { /* stub */ },

    /**
     * The tiny zoom bar shown on the bottom of a board (if showNavigation on board creation is true).
     * @param {JXG.Board} board Reference to a JSXGraph board.
     */
    drawZoomBar: function (board) { },

    /**
     * Wrapper for getElementById for maybe other renderers which elements are not directly accessible by DOM methods like document.getElementById().
     * @param {String} id Unique identifier for element.
     * @returns {Object} Reference to a JavaScript object. In case of SVG/VMLRenderer it's a reference to a SVG/VML node.
     */
    getElementById: function (id) {
        return null;
    },

    /**
     * Resizes the rendering element
     * @param {Number} w New width
     * @param {Number} h New height
     */
    resize: function (w, h) { /* stub */}

});

//JXG.NoRenderer.prototype = new JXG.AbstractRenderer();


/*
    Copyright 2008,
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * The FileReader object bundles the file input capabilities of JSXGraph.
 */
JXG.FileReader = {

    /**
     * Opens a file using the given URL and passes the contents to {@link JXG.FileReader#parseString}
     * @param {String} url
     * @param {JXG.Board|function} board Either a board or in case <tt>format</tt> equals 'raw' this has to be a callback function.
     * @param {String} format The expected file format. Possible values are <dl>
     * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd>
     * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd>
     * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd>
     * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd>
     * <dt>graph</dt><dd>Graph file</dd>
     * <dt>digraph</dt><dd>DiGraph file</dd>
     * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd>
     * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd>
     * </dl>
     * @param {Boolean} async Call ajax asynchonously.
     */
    parseFileContent: function (url, board, format, async) {
        var request = false;
        
        if(!JXG.exists(async)) {
            async = true;
        }

        //this.request = false;

        try {
            request = new XMLHttpRequest();
            if(format.toLowerCase()=='raw') {
                request.overrideMimeType('text/plain; charset=iso-8859-1');
            } else {
                request.overrideMimeType('text/xml; charset=iso-8859-1');
            }
        } catch (e) {
            try {
                request = new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                try {
                    request = new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e) {
                    request = false;
                }
            }
        }

        if (!request) {
            alert("AJAX not activated!");
            return;
        }
        
        request.open("GET", url, async);

        if(format.toLowerCase() === 'raw') {
            this.cbp = function() {
                var req = request;
                if (req.readyState == 4) {
                    board(req.responseText);
                }
            };
        } else {
            this.cbp = function() {
                var req = request;
                if (req.readyState == 4) {
                    var text = '';

                    if (typeof req.responseStream!='undefined' &&
                        (req.responseText.slice(0,2) == "PK"                            // ZIP -> Geogebra
                            || JXG.Util.asciiCharCodeAt(req.responseText.slice(0,1),0)==31) // gzip -> Cinderella
                        ) {
                        text = JXG.Util.Base64.decode(BinFileReader(req)); // After this, text contains the base64 encoded, zip-compressed string
                    } else {
                        text = req.responseText;
                    }
                    this.parseString(text, board, format, false);
                }
            };
        }

        this.cb = JXG.bind(this.cbp, this);
        request.onreadystatechange = this.cb;

        try {
            request.send(null);
        } catch (e) {
            throw new Error("JSXGraph: A problem occurred while trying to read '" + url + "'.");
        }
    },

    /**
     * Cleans out unneccessary whitespaces in a chunk of xml.
     * @param {XMLElement} el
     */
    cleanWhitespace: function (el) {
        var cur = el.firstChild;

        while (cur != null) {
            if (cur.nodeType == 3 && !/\S/.test(cur.nodeValue)) {
                el.removeChild( cur );
            } else if ( cur.nodeType == 1 ) {
                this.cleanWhitespace( cur );
            }
            cur = cur.nextSibling;
        }
    },

    /**
     * Converts a given string into a XML tree.
     * @param {String} str
     * @returns {XMLElement} The xml tree represented by the root node.
     */
    stringToXMLTree: function (str) {
        // The string "str" is converted into a XML tree.
        if(typeof DOMParser === 'undefined') {
            // IE workaround, since there is no DOMParser
            DOMParser = function () {};
            DOMParser.prototype.parseFromString = function (str, contentType) {
                if (typeof ActiveXObject !== 'undefined') {
                    var d = new ActiveXObject('MSXML.DomDocument');
                    d.loadXML(str);
                    return d;
                }
            };
        }
        var parser = new DOMParser(),
            tree = parser.parseFromString(str, 'text/xml');

        this.cleanWhitespace(tree);
        return tree;
    },

    /**
     * Parses a given string according to the file format given in format.
     * @param {String} str Contents of the file.
     * @param {JXG.Board} board The board the construction in the file should be loaded in.
     * @param {String} format Possible values are <dl>
     * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd>
     * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd>
     * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd>
     * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd>
     * <dt>graph</dt><dd>Graph file</dd>
     * <dt>digraph</dt><dd>DiGraph file</dd>
     * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd>
     * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd>
     * </dl>
     * @param {Boolean} isString Some file formats can be given as Base64 encoded strings or as plain xml, in both cases
     * they are given as strings. This flag is used to distinguish those cases: <tt>true</tt> means, it is given as a string,
     * no need to un-Base64 and unzip the file.
     */
    parseString: function (str, board, format, isString) {
        var tree, graph, xml;

        format = format.toLowerCase();

        switch (format) {
            case 'cdy':
            case 'cinderella':
                // if isString is true, str is the base64 encoded zip file, otherwise it's just the zip file
                if(isString) {
                    str = JXG.Util.Base64.decode(str);
                }

                str = JXG.CinderellaReader.readCinderella(str, board);
                board.xmlString = str;

                break;
            case 'tracenpoche':
                board.xmlString = JXG.TracenpocheReader.readTracenpoche(str, board);

                break;
            case 'graph':
                str = JXG.GraphReader.readGraph(str, board, false);
                break;
            case 'digraph':
                str = JXG.GraphReader.readGraph(str, board, true);
                break;
            case 'geonext':
                // str is a string containing the XML code of the construction
                str = JXG.GeonextReader.prepareString(str);
                xml = true;
                break;
            case 'geogebra':
                isString = str.slice(0, 2) !== "PK";

                // if isString is true, str is a base64 encoded string, otherwise it's the zipped file
                str = JXG.GeogebraReader.prepareString(str, isString);
                xml = true;
                break;
            case 'intergeo':
                if(isString) {
                    str = JXG.Util.Base64.decode(str);
                }

                str = JXG.IntergeoReader.prepareString(str);
                xml = true;
                break;
            case 'sketch':
                str = JXG.SketchReader.readSketch(str, board);
                break;
        }

        if (xml) {
            board.xmlString = str;
            tree = this.stringToXMLTree(str);
            // Now, we can walk through the tree
            this.readElements(tree, board, format);
        }
    },

    /**
     * Reading the elements of a geonext or geogebra file
     * @param {} tree expects the content of the parsed geonext file returned by function parseFromString
     * @param {Object} board board object
     */
    readElements: function (tree, board, format) {
        if (format.toLowerCase()=='geonext') {
            board.suspendUpdate();
            if(tree.getElementsByTagName('GEONEXT').length != 0) {
                JXG.GeonextReader.readGeonext(tree, board);
            }
            board.unsuspendUpdate();
        }
        else if(tree.getElementsByTagName('geogebra').length != 0) {
            JXG.GeogebraReader.readGeogebra(tree, board);
        }
        else if(format.toLowerCase()=='intergeo') {
            JXG.IntergeoReader.readIntergeo(tree, board);
        }
    }
};

// The following code is vbscript. This is a workaround to enable binary data downloads via AJAX in
// Microsoft Internet Explorer.
if(!JXG.isMetroApp() && typeof navigator !== 'undefined' && /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent && document && document.write)) {
document.write('<script type="text/vbscript">\n\
Function Base64Encode(inData)\n\
  Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"\n\
  Dim cOut, sOut, I\n\
  For I = 1 To LenB(inData) Step 3\n\
    Dim nGroup, pOut, sGroup\n\
    nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\n\
      &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\n\
    nGroup = Oct(nGroup)\n\
    nGroup = String(8 - Len(nGroup), "0") & nGroup\n\
    pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _\n\
      Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _\n\
      Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _\n\
      Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)\n\
    sOut = sOut + pOut\n\
  Next\n\
  Select Case LenB(inData) Mod 3\n\
    Case 1: \'8 bit final\n\
      sOut = Left(sOut, Len(sOut) - 2) + "=="\n\
    Case 2: \'16 bit final\n\
      sOut = Left(sOut, Len(sOut) - 1) + "="\n\
  End Select\n\
  Base64Encode = sOut\n\
End Function\n\
\n\
Function MyASC(OneChar)\n\
  If OneChar = "" Then MyASC = 0 Else MyASC = AscB(OneChar)\n\
End Function\n\
\n\
Function BinFileReader(xhr)\n\
    Dim byteString\n\
    Dim b64String\n\
    Dim i\n\
    byteString = xhr.responseBody\n\
    ReDim byteArray(LenB(byteString))\n\
    For i = 1 To LenB(byteString)\n\
        byteArray(i-1) = AscB(MidB(byteString, i, 1))\n\
    Next\n\
    b64String = Base64Encode(byteString)\n\
    BinFileReader = b64String\n\
End Function\n\
</script>\n');
}


/*
    Copyright 2008-2010,
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.

*/


/**
 * Parser helper routines. The methods in here are for parsing expressions in Geonext Syntax.
 * @namespace
 */

JXG.GeonextParser = {};

/**
 * Converts expression of the form <i>leftop^rightop</i> into <i>Math.pow(leftop,rightop)</i>.
 * @param {String} te Expression of the form <i>leftop^rightop</i>
 * @type String
 * @return Converted expression.
 */
JXG.GeonextParser.replacePow = function(te) {
    var count, pos, c,
        leftop, rightop, pre, p, left, i, right, expr;
    //te = te.replace(/\s+/g,''); // Loesche allen whitespace
                                // Achtung: koennte bei Variablennamen mit Leerzeichen
                                // zu Problemen fuehren.
                                
    te = te.replace(/(\s*)\^(\s*)/g,'\^'); // delete all whitespace immediately before and after all ^ operators

	//  Loop over all ^ operators
    i = te.indexOf('^');
    while (i>=0) {
		// left and right are the substrings before, resp. after the ^ character
        left = te.slice(0,i);
        right = te.slice(i+1);

		// If there is a ")" immediately before the ^ operator, it can be the end of a
		// (i) term in parenthesis
		// (ii) function call
		// (iii) method  call
		// In either case, first the corresponding opening parenthesis is searched.
		// This is the case, when count==0
        if (left.charAt(left.length-1)==')') {
            count = 1;
            pos = left.length-2;
            while (pos>=0 && count>0) {
                c = left.charAt(pos);
                if (c==')') { count++; }
                else if (c=='(') { count--; }
                pos--;
            }   
            if (count==0) {
				// Now, we have found the opning parenthesis and we have to look
				// if it is (i), or (ii), (iii).
                leftop = '';
                pre = left.substring(0,pos+1);   // Search for F or p.M before (...)^
                p = pos;
                while (p>=0 && pre.substr(p,1).match(/([\w\.]+)/)) { 
                    leftop = RegExp.$1+leftop;
                    p--;
                }
                leftop += left.substring(pos+1,left.length);
                leftop = leftop.replace(/([\(\)\+\*\%\^\-\/\]\[])/g,"\\$1");
            } else {
				throw new Error("JSXGraph: Missing '(' in expression");
			}
        } else {
            //leftop = '[\\w\\.\\(\\)\\+\\*\\%\\^\\-\\/\\[\\]]+'; // former: \\w\\. . Doesn't work for sin(x^2)
   			// Otherwise, the operand has to be a constant (or variable).
         leftop = '[\\w\\.]+'; // former: \\w\\.
        }
		// To the right of the ^ operator there also may be a function or method call
		// or a term in parenthesis. Alos, ere we search for the closing
		// parenthesis.
        if (right.match(/^([\w\.]*\()/)) {
            count = 1;
            pos = RegExp.$1.length;
            while (pos<right.length && count>0) {
                c = right.charAt(pos);
                if (c==')') { count--; }
                else if (c=='(') { count++; }
                pos++;
            }
            if (count==0) {
                rightop = right.substring(0,pos);
                rightop = rightop.replace(/([\(\)\+\*\%\^\-\/\[\]])/g,"\\$1");
            } else {
				throw new Error("JSXGraph: Missing ')' in expression");
			}
        } else {
            //rightop = '[\\w\\.\\(\\)\\+\\*\\%\\^\\-\\/\\[\\]]+';  // ^b , see leftop. Doesn't work for sin(x^2)
			// Otherwise, the operand has to be a constant (or variable).
            rightop = '[\\w\\.]+';  
        }
		// Now, we have the two operands and replace ^ by JXG.Math.pow
        expr = new RegExp('(' + leftop + ')\\^(' + rightop + ')');
        te = te.replace(expr,"JXG.Math.pow($1,$2)");
        i = te.indexOf('^');
    }
    return te;
};

/**
 * Converts expression of the form <i>If(a,b,c)</i> into <i>(a)?(b):(c)/i>.
 * @param {String} te Expression of the form <i>If(a,b,c)</i>
 * @type String
 * @return Converted expression.
 */
JXG.GeonextParser.replaceIf = function(te) {
    var s = '',
        left, right,
        first = null,
        second = null,
        third = null,
        i, pos, count, k1, k2, c, meat;
    
    i = te.indexOf('If(');
    if (i<0) { return te; }

    te = te.replace(/""/g,'0'); // "" means not defined. Here, we replace it by 0
    while (i>=0) {
        left = te.slice(0,i);
        right = te.slice(i+3); 
        
        // Search the end of the If() command and take out the meat
        count = 1;
        pos = 0;
        k1 = -1;
        k2 = -1;
        while (pos<right.length && count>0) {
            c = right.charAt(pos);
            if (c==')') { 
                count--;
            } else if (c=='(') {
                count++;
            } else if (c==',' && count==1) {
                if (k1<0) { 
                    k1 = pos; // first komma
                } else {
                    k2 = pos; // second komma
                }
            }
            pos++;
        } 
        meat = right.slice(0,pos-1);
        right = right.slice(pos);
        
        // Test the two kommas
        if (k1<0) { return ''; } // , missing
        if (k2<0) { return ''; } // , missing
        
        first = meat.slice(0,k1);
        second = meat.slice(k1+1,k2);
        third = meat.slice(k2+1);
        first = this.replaceIf(first);    // Recurse
        second = this.replaceIf(second);  // Recurse
        third = this.replaceIf(third);    // Recurse

        s += left + '((' + first + ')?' + '('+second+'):('+third+'))';  
        te = right;
        first = null;
        second = null;
        i = te.indexOf('If(');
    }
    s += right;
    return s;
};

/**
 * Replace _{} by &lt;sub&gt;
 * @param {String} the String containing _{}.
 * @type String
 * @return Given string with _{} replaced by &lt;sub&gt;.
 */
JXG.GeonextParser.replaceSub = function(te) {
    if(te['indexOf']) {} else return te;

    var i = te.indexOf('_{'),
        j;
    while (i>=0) {
        te = te.substr(0,i)+te.substr(i).replace(/_\{/,'<sub>');
        j = te.substr(i).indexOf('}');
        if (j>=0) {
            te = te.substr(0,j)+te.substr(j).replace(/\}/,'</sub>');
        }
        i = te.indexOf('_{');
    }

    i = te.indexOf('_');
    while (i>=0) {
        te = te.substr(0,i)+te.substr(i).replace(/_(.?)/,'<sub>$1</sub>');
        i = te.indexOf('_');
    }
    return te;
};

/**
 * Replace ^{} by &lt;sup&gt;
 * @param {String} the String containing ^{}.
 * @type String
 * @return Given string with ^{} replaced by &lt;sup&gt;.
 */
JXG.GeonextParser.replaceSup = function(te) {
    if(te['indexOf']) {} else return te;

    var i = te.indexOf('^{'),
        j;
    while (i>=0) {
        te = te.substr(0,i)+te.substr(i).replace(/\^\{/,'<sup>');
        j = te.substr(i).indexOf('}');
        if (j>=0) {
            te = te.substr(0,j)+te.substr(j).replace(/\}/,'</sup>');
        }
        i = te.indexOf('^{');
    }

    i = te.indexOf('^');
    while (i>=0) {
        te = te.substr(0,i)+te.substr(i).replace(/\^(.?)/,'<sup>$1</sup>');
        i = te.indexOf('^');
    }

    return te;
};

/**
 * Replace an element's name in terms by an element's id.
 * @param term Term containing names of elements.
 * @param board Reference to the board the elements are on.
 * @return The same string with names replaced by ids.
 **/
JXG.GeonextParser.replaceNameById = function(/** string */ term, /** JXG.Board */ board) /** string */ {
    var pos = 0, end, elName, el, i,
        funcs = ['X','Y','L','V'];

    //    
    // Find X(el), Y(el), ... 
    // All functions declared in funcs
    for (i=0;i<funcs.length;i++) {
        pos = term.indexOf(funcs[i]+'(');
        while (pos>=0) {
            if (pos>=0) {
                end = term.indexOf(')',pos+2);
                if (end>=0) {
                    elName = term.slice(pos+2,end);
                    elName = elName.replace(/\\(['"])?/g,"$1");
                    el = board.elementsByName[elName];
                    term = term.slice(0,pos+2) + el.id +  term.slice(end);
                }
            }
            end = term.indexOf(')',pos+2);
            pos = term.indexOf(funcs[i]+'(',end);
        }
    }

    pos = term.indexOf('Dist(');
    while (pos>=0) {
        if (pos>=0) {
            end = term.indexOf(',',pos+5);
            if (end>=0) {
                elName = term.slice(pos+5,end);
                elName = elName.replace(/\\(['"])?/g,"$1");
                el = board.elementsByName[elName];
                term = term.slice(0,pos+5) + el.id +  term.slice(end);
            }
        }
        end = term.indexOf(',',pos+5);
        pos = term.indexOf(',',end);
        end = term.indexOf(')',pos+1);
        if (end>=0) {
            elName = term.slice(pos+1,end);
            elName = elName.replace(/\\(['"])?/g,"$1");
            el = board.elementsByName[elName];
            term = term.slice(0,pos+1) + el.id +  term.slice(end);
        }
        end = term.indexOf(')',pos+1);
        pos = term.indexOf('Dist(',end);
    }

    funcs = ['Deg','Rad'];
    for (i=0;i<funcs.length;i++) {
        pos = term.indexOf(funcs[i]+'(');
        while (pos>=0) {
            if (pos>=0) {
                end = term.indexOf(',',pos+4);
                if (end>=0) {
                    elName = term.slice(pos+4,end);
                    elName = elName.replace(/\\(['"])?/g,"$1");
                    el = board.elementsByName[elName];
                    term = term.slice(0,pos+4) + el.id +  term.slice(end);
                }
            }
            end = term.indexOf(',',pos+4);
            pos = term.indexOf(',',end);
            end = term.indexOf(',',pos+1);
            if (end>=0) {
                elName = term.slice(pos+1,end);
                elName = elName.replace(/\\(['"])?/g,"$1");
                el = board.elementsByName[elName];
                term = term.slice(0,pos+1) + el.id +  term.slice(end);
            }
            end = term.indexOf(',',pos+1);
            pos = term.indexOf(',',end);
            end = term.indexOf(')',pos+1);
            if (end>=0) {
                elName = term.slice(pos+1,end);
                elName = elName.replace(/\\(['"])?/g,"$1");
                el = board.elementsByName[elName];
                term = term.slice(0,pos+1) + el.id +  term.slice(end);
            }
            end = term.indexOf(')',pos+1);
            pos = term.indexOf(funcs[i]+'(',end);
        }
    }
    return term;
};

/**
 * Replaces element ids in terms by element this.board.objects['id'].
 * @param term A GEONE<sub>x</sub>T function string with JSXGraph ids in it.
 * @return The input string with element ids replaced by this.board.objects["id"]. 
 **/
JXG.GeonextParser.replaceIdByObj = function(/** string */ term) /** string */ {
    var expr = /(X|Y|L)\(([\w_]+)\)/g;  // Suche "X(gi23)" oder "Y(gi23A)" und wandle in objects['gi23'].X() um.
    term = term.replace(expr,"this.board.objects[\"$2\"].$1()");
    
    expr = /(V)\(([\w_]+)\)/g;  // Suche "X(gi23)" oder "Y(gi23A)" und wandle in objects['gi23'].X() um.
    term = term.replace(expr,"this.board.objects[\"$2\"].Value()");

    expr = /(Dist)\(([\w_]+),([\w_]+)\)/g;  // 
    term = term.replace(expr,'this.board.objects[\"$2\"].Dist(this.board.objects[\"$3\"])');

    expr = /(Deg)\(([\w_]+),([ \w\[\w_]+),([\w_]+)\)/g;  // 
    term = term.replace(expr,'JXG.Math.Geometry.trueAngle(this.board.objects[\"$2\"],this.board.objects[\"$3\"],this.board.objects[\"$4\"])');

    expr = /Rad\(([\w_]+),([\w_]+),([\w_]+)\)/g;  // Suche Rad('gi23','gi24','gi25')
    term = term.replace(expr,'JXG.Math.Geometry.rad(this.board.objects[\"$1\"],this.board.objects[\"$2\"],this.board.objects[\"$3\"])');

    expr = /N\((.+)\)/g;  // 
    term = term.replace(expr,'($1)');

    return term;
};

/**
 * Converts the given algebraic expression in GEONE<sub>x</sub>T syntax into an equivalent expression in JavaScript syntax.
 * @param {String} term Expression in GEONExT syntax
 * @type String
 * @return Given expression translated to JavaScript.
 */
JXG.GeonextParser.geonext2JS = function(term, board) {
    var expr, newterm, i,
        from = ['Abs', 'ACos', 'ASin', 'ATan','Ceil','Cos','Exp','Factorial','Floor','Log','Max','Min','Random','Round','Sin','Sqrt','Tan','Trunc'], 
        to =   ['Math.abs', 'Math.acos', 'Math.asin', 'Math.atan', 'Math.ceil', 'Math.cos', 'Math.exp', 'JXG.Math.factorial','Math.floor', 'Math.log', 'Math.max', 'Math.min', 'Math.random', 'this.board.round', 'Math.sin', 'Math.sqrt', 'Math.tan', 'Math.ceil'];
    // removed: 'Pow'  -> Math.pow
    
    //term = JXG.unescapeHTML(term);  // This replaces &gt; by >, &lt; by < and &amp; by &. But it is to strict. 
    term = term.replace(/&lt;/g,'<'); // Hacks, to enable not well formed XML, @see JXG.GeonextReader#replaceLessThan
    term = term.replace(/&gt;/g,'>'); 
    term = term.replace(/&amp;/g,'&'); 
    
    // Umwandeln der GEONExT-Syntax in JavaScript-Syntax
    newterm = term;
    newterm = this.replaceNameById(newterm, board);
    newterm = this.replaceIf(newterm);
    // Exponentiations-Problem x^y -> Math(exp(x,y).
    newterm = this.replacePow(newterm);
    newterm = this.replaceIdByObj(newterm);
    for (i=0; i<from.length; i++) {
        expr = new RegExp(['(\\W|^)(',from[i],')'].join(''),"ig");  // sin -> Math.sin and asin -> Math.asin 
        newterm = newterm.replace(expr,['$1',to[i]].join(''));
    } 
    newterm = newterm.replace(/True/g,'true');
    newterm = newterm.replace(/False/g,'false');
    newterm = newterm.replace(/fasle/g,'false');

    newterm = newterm.replace(/Pi/g,'Math.PI');
    return newterm;
};

/**
 * Finds dependencies in a given term and resolves them by adding the
 * dependent object to the found objects child elements.
 * @param {JXG.GeometryElement} me Object depending on objects in given term.
 * @param {String} term String containing dependencies for the given object.
 * @param {JXG.Board} [board=me.board] Reference to a board
 */
JXG.GeonextParser.findDependencies = function(me, term, board) {
    if(typeof board=='undefined')
        board = me.board;

    var elements = board.elementsByName,
        el, expr, elmask;

    for (el in elements) {
        if (el != me.name) {
            if(elements[el].type == JXG.OBJECT_TYPE_TEXT) {
                if(!elements[el].visProp.islabel) {
                    elmask = el.replace(/\[/g,'\\[');
                    elmask = elmask.replace(/\]/g,'\\]');
                    expr = new RegExp("\\(\(\[\\w\\[\\]'_ \]+,\)*\("+elmask+"\)\(,\[\\w\\[\\]'_ \]+\)*\\)","g");  // Searches (A), (A,B),(A,B,C)
                    if (term.search(expr)>=0) {
                        elements[el].addChild(me);
                    }
                }
            }
            else {
                elmask = el.replace(/\[/g,'\\[');
                elmask = elmask.replace(/\]/g,'\\]');
                expr = new RegExp("\\(\(\[\\w\\[\\]'_ \]+,\)*\("+elmask+"\)\(,\[\\w\\[\\]'_ \]+\)*\\)","g");  // Searches (A), (A,B),(A,B,C)
                if (term.search(expr)>=0) {
                    elements[el].addChild(me);
                }
            }
        }
    }
};

/**
 * Converts the given algebraic expression in GEONE<sub>x</sub>T syntax into an equivalent expression in JavaScript syntax.
 * @param {String} term Expression in GEONExT syntax
 * @type String
 * @return Given expression translated to JavaScript.
 */
JXG.GeonextParser.gxt2jc = function(term, board) {
    var newterm,
		from = ['Sqrt'],
		to = ['sqrt'];
    
    term = term.replace(/&lt;/g,'<'); // Hacks, to enable not well formed XML, @see JXG.GeonextReader#replaceLessThan
    term = term.replace(/&gt;/g,'>'); 
    term = term.replace(/&amp;/g,'&'); 
    newterm = term;
    newterm = this.replaceNameById2(newterm, board);
	/*
    for (i=0; i<from.length; i++) {
        expr = new RegExp(['(\\W|^)(',from[i],')'].join(''),"ig");  // sin -> Math.sin and asin -> Math.asin 
        newterm = newterm.replace(expr,['$1',to[i]].join(''));
    } 
	*/
    newterm = newterm.replace(/True/g,'true');
    newterm = newterm.replace(/False/g,'false');
    newterm = newterm.replace(/fasle/g,'false');

    return newterm;
};

/**
 * Replace an element's name in terms by an element's id.
 * @param term Term containing names of elements.
 * @param board Reference to the board the elements are on.
 * @return The same string with names replaced by ids.
 **/
JXG.GeonextParser.replaceNameById2 = function(/** string */ term, /** JXG.Board */ board) /** string */ {
    var pos = 0, end, elName, el, i,
        funcs = ['X','Y','L','V'];

    //    
    // Find X(el), Y(el), ... 
    // All functions declared in funcs
    for (i=0;i<funcs.length;i++) {
        pos = term.indexOf(funcs[i]+'(');
        while (pos>=0) {
            if (pos>=0) {
                end = term.indexOf(')',pos+2);
                if (end>=0) {
                    elName = term.slice(pos+2,end);
                    elName = elName.replace(/\\(['"])?/g,"$1");
                    el = board.elementsByName[elName];
                    term = term.slice(0,pos+2) + "$('"+el.id +"')" +  term.slice(end);
                }
            }
            end = term.indexOf(')',pos+2);
            pos = term.indexOf(funcs[i]+'(',end);
        }
    }

    pos = term.indexOf('Dist(');
    while (pos>=0) {
        if (pos>=0) {
            end = term.indexOf(',',pos+5);
            if (end>=0) {
                elName = term.slice(pos+5,end);
                elName = elName.replace(/\\(['"])?/g,"$1");
                el = board.elementsByName[elName];
                term = term.slice(0,pos+5) + "$('"+el.id +"')" +  term.slice(end);
            }
        }
        end = term.indexOf(',',pos+5);
        pos = term.indexOf(',',end);
        end = term.indexOf(')',pos+1);
        if (end>=0) {
            elName = term.slice(pos+1,end);
            elName = elName.replace(/\\(['"])?/g,"$1");
            el = board.elementsByName[elName];
            term = term.slice(0,pos+1) + "$('"+el.id +"')" +  term.slice(end);
        }
        end = term.indexOf(')',pos+1);
        pos = term.indexOf('Dist(',end);
    }

    funcs = ['Deg','Rad'];
    for (i=0;i<funcs.length;i++) {
        pos = term.indexOf(funcs[i]+'(');
        while (pos>=0) {
            if (pos>=0) {
                end = term.indexOf(',',pos+4);
                if (end>=0) {
                    elName = term.slice(pos+4,end);
                    elName = elName.replace(/\\(['"])?/g,"$1");
                    el = board.elementsByName[elName];
                    term = term.slice(0,pos+4) + "$('"+el.id +"')" +  term.slice(end);
                }
            }
            end = term.indexOf(',',pos+4);
            pos = term.indexOf(',',end);
            end = term.indexOf(',',pos+1);
            if (end>=0) {
                elName = term.slice(pos+1,end);
                elName = elName.replace(/\\(['"])?/g,"$1");
                el = board.elementsByName[elName];
                term = term.slice(0,pos+1) + "$('"+el.id +"')" +  term.slice(end);
            }
            end = term.indexOf(',',pos+1);
            pos = term.indexOf(',',end);
            end = term.indexOf(')',pos+1);
            if (end>=0) {
                elName = term.slice(pos+1,end);
                elName = elName.replace(/\\(['"])?/g,"$1");
                el = board.elementsByName[elName];
                term = term.slice(0,pos+1) + "$('"+el.id +"')" +  term.slice(end);
            }
            end = term.indexOf(')',pos+1);
            pos = term.indexOf(funcs[i]+'(',end);
        }
    }
    return term;
};



/*
    Copyright 2008-2012
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/*global JXG: true, AMprocessNode: true, MathJax: true, document: true, init: true, translateASCIIMath: true */

/**
 * @fileoverview The JXG.Board class is defined in this file. JXG.Board controls all properties and methods
 * used to manage a geonext board like managing geometric elements, managing mouse and touch events, etc.
 * @author graphjs
 * @version 0.1
 */

'use strict';

/**
 * Constructs a new Board object.
 * @class JXG.Board controls all properties and methods used to manage a geonext board like managing geometric
 * elements, managing mouse and touch events, etc. You probably don't want to use this constructor directly.
 * Please use {@link JXG.JSXGraph#initBoard} to initialize a board.
 * @constructor
 * @param {String} container The id or reference of the HTML DOM element the board is drawn in. This is usually a HTML div.
 * @param {JXG.AbstractRenderer} renderer The reference of a renderer.
 * @param {String} id Unique identifier for the board, may be an empty string or null or even undefined.
 * @param {JXG.Coords} origin The coordinates where the origin is placed, in user coordinates.
 * @param {Number} zoomX Zoom factor in x-axis direction
 * @param {Number} zoomY Zoom factor in y-axis direction
 * @param {Number} unitX Units in x-axis direction
 * @param {Number} unitY Units in y-axis direction
 * @param {Number} canvasWidth  The width of canvas
 * @param {Number} canvasHeight The height of canvas
 * @param {Boolean} showCopyright Display the copyright text
 * @borrows JXG.EventEmitter#on as this.on
 * @borrows JXG.EventEmitter#off as this.off
 * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers
 * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers
 */
JXG.Board = function (container, renderer, id, origin, zoomX, zoomY, unitX, unitY, canvasWidth, canvasHeight, showCopyright) {
    /**
     * Board is in no special mode, objects are highlighted on mouse over and objects may be
     * clicked to start drag&drop.
     * @type Number
     * @constant
     */
    this.BOARD_MODE_NONE = 0x0000;

    /**
     * Board is in drag mode, objects aren't highlighted on mouse over and the object referenced in
     * {JXG.Board#mouse} is updated on mouse movement.
     * @type Number
     * @constant
     * @see JXG.Board#drag_obj
     */
    this.BOARD_MODE_DRAG = 0x0001;

    /**
     * In this mode a mouse move changes the origin's screen coordinates.
     * @type Number
     * @constant
     */
    this.BOARD_MODE_MOVE_ORIGIN = 0x0002;

    /**
     * Update is made with low quality, e.g. graphs are evaluated at a lesser amount of points.
     * @type Number
     * @constant
     * @see JXG.Board#updateQuality
     */
    this.BOARD_QUALITY_LOW = 0x1;

    /**
     * Update is made with high quality, e.g. graphs are evaluated at much more points.
     * @type Number
     * @constant
     * @see JXG.Board#updateQuality
     */
    this.BOARD_QUALITY_HIGH = 0x2;

    /**
     * Update is made with high quality, e.g. graphs are evaluated at much more points.
     * @type Number
     * @constant
     * @see JXG.Board#updateQuality
     */
    this.BOARD_MODE_ZOOM = 0x0011;

    /**
     * The html-id of the html element containing the board.
     * @type String
     */
    this.container = container;

    /**
     * Pointer to the html element containing the board.
     * @type Object
     */
    this.containerObj = (JXG.isBrowser ? document.getElementById(this.container) : null);

    if (JXG.isBrowser && this.containerObj === null) {
        throw new Error("\nJSXGraph: HTML container element '" + (container) + "' not found.");
    }

    /**
     * A reference to this boards renderer.
     * @type JXG.AbstractRenderer
     */
    this.renderer = renderer;

    /**
     * Grids keeps track of all grids attached to this board.
     */
    this.grids = [];

    /**
     * Some standard options
     * @type JXG.Options
     */
    this.options = JXG.deepCopy(JXG.Options);

    /**
     * Dimension of the board.
     * @default 2
     * @type Number
     */
    this.dimension = 2;

    this.jc = new JXG.JessieCode();
    this.jc.use(this);

    /**
     * Coordinates of the boards origin. This a object with the two properties
     * usrCoords and scrCoords. usrCoords always equals [1, 0, 0] and scrCoords
     * stores the boards origin in homogeneous screen coordinates.
     * @type Object
     */
    this.origin = {};
    this.origin.usrCoords = [1, 0, 0];
    this.origin.scrCoords = [1, origin[0], origin[1]];

    /**
     * Zoom factor in X direction. It only stores the zoom factor to be able
     * to get back to 100% in zoom100().
     * @type Number
     */
    this.zoomX = zoomX;

    /**
     * Zoom factor in Y direction. It only stores the zoom factor to be able
     * to get back to 100% in zoom100().
     * @type Number
     */
    this.zoomY = zoomY;

    /**
     * The number of pixels which represent one unit in user-coordinates in x direction.
     * @type Number
     */
    this.unitX = unitX * this.zoomX;

    /**
     * The number of pixels which represent one unit in user-coordinates in y direction.
     * @type Number
     */
    this.unitY = unitY * this.zoomY;

    /**
     * Canvas width.
     * @type Number
     */
    this.canvasWidth = canvasWidth;

    /**
     * Canvas Height
     * @type Number
     */
    this.canvasHeight = canvasHeight;

    // If the given id is not valid, generate an unique id
    if (JXG.exists(id) && id !== '' && JXG.isBrowser && !JXG.exists(document.getElementById(id))) {
        this.id = id;
    } else {
        this.id = this.generateId();
    }

    JXG.EventEmitter.eventify(this);

    this.hooks = [];

    /**
     * An array containing all other boards that are updated after this board has been updated.
     * @type Array
     * @see JXG.Board#addChild
     * @see JXG.Board#removeChild
     */
    this.dependentBoards = [];

    /**
     * During the update process this is set to false to prevent an endless loop.
     * @default false
     * @type Boolean
     */
    this.inUpdate = false;

    /**
     * An associative array containing all geometric objects belonging to the board. Key is the id of the object and value is a reference to the object.
     * @type Object
     */
    this.objects = {};

    /**
     * An array containing all geometric objects on the board in the order of construction.
     * @type {Array}
     */
    this.objectsList = [];

    /**
     * An associative array containing all groups belonging to the board. Key is the id of the group and value is a reference to the object.
     * @type Object
     */
    this.groups = {};

    /**
     * Stores all the objects that are currently running an animation.
     * @type Object
     */
    this.animationObjects = {};

    /**
     * An associative array containing all highlighted elements belonging to the board.
     * @type Object
     */
    this.highlightedObjects = {};

    /**
     * Number of objects ever created on this board. This includes every object, even invisible and deleted ones.
     * @type Number
     */
    this.numObjects = 0;

    /**
     * An associative array to store the objects of the board by name. the name of the object is the key and value is a reference to the object.
     * @type Object
     */
    this.elementsByName = {};

    /**
     * The board mode the board is currently in. Possible values are
     * <ul>
     * <li>JXG.Board.BOARD_MODE_NONE</li>
     * <li>JXG.Board.BOARD_MODE_DRAG</li>
     * <li>JXG.Board.BOARD_MODE_MOVE_ORIGIN</li>
     * </ul>
     * @type Number
     */
    this.mode = this.BOARD_MODE_NONE;

    /**
     * The update quality of the board. In most cases this is set to {@link JXG.Board#BOARD_QUALITY_HIGH}.
     * If {@link JXG.Board#mode} equals {@link JXG.Board#BOARD_MODE_DRAG} this is set to
     * {@link JXG.Board#BOARD_QUALITY_LOW} to speed up the update process by e.g. reducing the number of
     * evaluation points when plotting functions. Possible values are
     * <ul>
     * <li>BOARD_QUALITY_LOW</li>
     * <li>BOARD_QUALITY_HIGH</li>
     * </ul>
     * @type Number
     * @see JXG.Board#mode
     */
    this.updateQuality = this.BOARD_QUALITY_HIGH;

   /**
     * If true updates are skipped.
     * @type Boolean
     */
    this.isSuspendedRedraw = false;

    this.calculateSnapSizes();

    /**
     * The distance from the mouse to the dragged object in x direction when the user clicked the mouse button.
     * @type Number
     * @see JXG.Board#drag_dy
     * @see JXG.Board#drag_obj
     */
    this.drag_dx = 0;

    /**
     * The distance from the mouse to the dragged object in y direction when the user clicked the mouse button.
     * @type Number
     * @see JXG.Board#drag_dx
     * @see JXG.Board#drag_obj
     */
    this.drag_dy = 0;

    /**
     * References to the object that is dragged with the mouse on the board.
     * @type {@link JXG.GeometryElement}.
     * @see {JXG.Board#touches}
     */
    this.mouse = null;

    /**
     * Keeps track on touched elements, like {@link JXG.Board#mouse} does for mouse events.
     * @type Array
     * @see {JXG.Board#mouse}
     */
    this.touches = [];

    /**
     * A string containing the XML text of the construction. This is set in {@link JXG.FileReader#parseString}.
     * Only useful if a construction is read from a GEONExT-, Intergeo-, Geogebra-, or Cinderella-File.
     * @type String
     */
    this.xmlString = '';

    /**
     * Cached ressult of getCoordsTopLeftCorner for touch/mouseMove-Events to save some DOM operations.
     * @type Array
     */
    this.cPos = [];

    /**
     * Contains the last time (epoch, msec) since the last touchMove event which was not thrown away or since
     * touchStart because Android's Webkit browser fires too much of them.
     * @type Number
     */
    this.touchMoveLast = 0;

    /**
     * Collects all elements that triggered a mouse down event.
     * @type Array
     */
    this.downObjects = [];

    /**
     * Display the licence text.
     * @see JXG.JSXGraph#licenseText
     * @see JXG.JSXGraph#initBoard
     */
    this.showCopyright = false;
    if ((showCopyright !== null && showCopyright) || (showCopyright === null && this.options.showCopyright)) {
        this.showCopyright = true;
        this.renderer.displayCopyright(JXG.JSXGraph.licenseText, parseInt(this.options.text.fontSize, 10));
    }

    /**
     * Full updates are needed after zoom and axis translates. This saves some time during an update.
     * @default false
     * @type Boolean
     */
    this.needsFullUpdate = false;

    /**
     * If reducedUpdate is set to true then only the dragged element and few (e.g. 2) following
     * elements are updated during mouse move. On mouse up the whole construction is
     * updated. This enables us to be fast even on very slow devices.
     * @type Boolean
     * @default false
     */
    this.reducedUpdate = false;

    /**
     * The current color blindness deficiency is stored in this property. If color blindness is not emulated
     * at the moment, it's value is 'none'.
     */
    this.currentCBDef = 'none';

    /**
     * If GEONExT constructions are displayed, then this property should be set to true.
     * At the moment there should be no difference. But this may change.
     * This is set in {@link JXG.GeonextReader#readGeonext}.
     * @type Boolean
     * @default false
     * @see JXG.GeonextReader#readGeonext
     */
    this.geonextCompatibilityMode = false;

    if (this.options.text.useASCIIMathML && translateASCIIMath) {
        init();
    } else {
        this.options.text.useASCIIMathML = false;
    }

    /**
     * A flag which tells if the board registers mouse events.
     * @type Boolean
     * @default true
     */
    this.hasMouseHandlers = false;

    /**
     * A flag which tells if the board registers touch events.
     * @type Boolean
     * @default true
     */
    this.hasTouchHandlers = false;

    /**
     * A flag which tells if the board the JXG.Board#mouseUpListener is currently registered.
     * @type Boolean
     * @default false
     */
    this.hasMouseUp = false;

    /**
     * A flag which tells if the board the JXG.Board#touchEndListener is currently registered.
     * @type Boolean
     * @default false
     */
    this.hasTouchEnd = false;

    this.addEventHandlers();

    this.methodMap = {
        update: 'update',
        on: 'on',
        off: 'off',
        setView: 'setBoundingBox',
        setBoundingBox: 'setBoundingBox',
        migratePoint: 'migratePoint',
        colorblind: 'emulateColorblindness'
    };
};

JXG.extend(JXG.Board.prototype, /** @lends JXG.Board.prototype */ {

    /**
     * Generates an unique name for the given object. The result depends on the objects type, if the
     * object is a {@link JXG.Point}, capital characters are used, if it is of type {@link JXG.Line}
     * only lower case characters are used. If object is of type {@link JXG.Polygon}, a bunch of lower
     * case characters prefixed with P_ are used. If object is of type {@link JXG.Circle} the name is
     * generated using lower case characters. prefixed with k_ is used. In any other case, lower case
     * chars prefixed with s_ is used.
     * @param {Object} object Reference of an JXG.GeometryElement that is to be named.
     * @returns {String} Unique name for the object.
     */
    generateName: function (object) {
        var possibleNames, i, j, length,
            maxNameLength = 2,
            pre = '',
            post = '',
            indices = [],
            name = '';

        if (object.type === JXG.OBJECT_TYPE_TICKS) {
            return '';
        }

        if (object.elementClass === JXG.OBJECT_CLASS_POINT) {
            // points have capital letters
            possibleNames = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
                'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
        } else if (object.type === JXG.OBJECT_TYPE_ANGLE) {
            possibleNames = ['', '&alpha;', '&beta;', '&gamma;', '&delta;', '&epsilon;', '&zeta;', '&eta;', '&theta;',
                '&iota;', '&kappa;', '&lambda;', '&mu;', '&nu;', '&xi;', '&omicron;', '&pi;', '&rho;',
                '&sigma;', '&tau;', '&upsilon;', '&phi;', '&chi;', '&psi;', '&omega;'];
        } else {
            // all other elements get lowercase labels
            possibleNames = ['', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
                'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
        }

        if (object.elementClass !== JXG.OBJECT_CLASS_POINT &&
                object.elementClass !== JXG.OBJECT_CLASS_LINE &&
                object.type !== JXG.OBJECT_TYPE_ANGLE) {
            if (object.type === JXG.OBJECT_TYPE_POLYGON) {
                pre = 'P_{';
            } else if (object.elementClass === JXG.OBJECT_CLASS_CIRCLE) {
                pre = 'k_{';
            } else if (object.type === JXG.OBJECT_TYPE_TEXT) {
                pre = 't_{';
            } else {
                pre = 's_{';
            }
            post = '}';
        }

        for (i = 0; i < maxNameLength; i++) {
            indices[i] = 0;
        }

        while (indices[maxNameLength - 1] < possibleNames.length) {
            for (indices[0] = 1; indices[0] < possibleNames.length; indices[0]++) {
                name = pre;

                for (i = maxNameLength; i > 0; i--) {
                    name += possibleNames[indices[i - 1]];
                }

                if (!JXG.exists(this.elementsByName[name + post])) {
                    return name + post;
                }

            }
            indices[0] = possibleNames.length;
            
            for (i = 1; i < maxNameLength; i++) {
                if (indices[i - 1] === possibleNames.length) {
                    indices[i - 1] = 1;
                    indices[i]++;
                }
            }
        }

        return '';
    },

    /**
     * Generates unique id for a board. The result is randomly generated and prefixed with 'jxgBoard'.
     * @returns {String} Unique id for a board.
     */
    generateId: function () {
        var r = 1;

        // as long as we don't have a unique id generate a new one
        while (JXG.exists(JXG.JSXGraph.boards['jxgBoard' + r])) {
            r = Math.round(Math.random() * 65535);
        }

        return ('jxgBoard' + r);
    },

    /**
     * Composes an id for an element. If the ID is empty ('' or null) a new ID is generated, depending on the
     * object type. Additionally, the id of the label is set. As a side effect {@link JXG.Board#numObjects}
     * is updated.
     * @param {Object} obj Reference of an geometry object that needs an id.
     * @param {Number} type Type of the object.
     * @returns {String} Unique id for an element.
     */
    setId: function (obj, type) {
        var num = this.numObjects++,
            elId = obj.id;

        // Falls Id nicht vorgegeben, eine Neue generieren:
        if (elId === '' || !JXG.exists(elId)) {
            elId = this.id + type + num;
        }

        obj.id = elId;
        this.objects[elId] = obj;
        obj._pos = this.objectsList.length;
        this.objectsList[this.objectsList.length] = obj;

        return elId;
    },

    /**
     * After construction of the object the visibility is set
     * and the label is constructed if necessary.
     * @param {Object} obj The object to add.
     */
    finalizeAdding: function (obj) {
        if (!obj.visProp.visible) {
            this.renderer.hide(obj);
        }
    },

    finalizeLabel: function (obj) {
        if (obj.hasLabel && !obj.label.content.visProp.islabel && !obj.label.content.visProp.visible) {
            this.renderer.hide(obj.label.content);
        }
    },

    /**********************************************************
     *
     * Event Handler helpers
     *
     **********************************************************/

    /**
     * Calculates mouse coordinates relative to the boards container.
     * @returns {Array} Array of coordinates relative the boards container top left corner.
     */
    getCoordsTopLeftCorner: function () {
        var pCont = this.containerObj,
            cPos = JXG.getOffset(pCont),
            doc = document.documentElement.ownerDocument,
            getProp = function (css) {
                var n = parseInt(JXG.getStyle(pCont, css), 10);
                return isNaN(n) ? 0 : n;
            };

        if (this.cPos.length > 0 && (this.mode === JXG.BOARD_MODE_DRAG || this.mode === JXG.BOARD_MODE_MOVE_ORIGIN)) {
            return this.cPos;
        }

        if (!pCont.currentStyle && doc.defaultView) {     // Non IE
            pCont = document.documentElement;

            // this is for hacks like this one used in wordpress for the admin bar:
            // html { margin-top: 28px }
            // seems like it doesn't work in IE

            cPos[0] += getProp('margin-left');
            cPos[1] += getProp('margin-top');

            cPos[0] += getProp('border-left-width');
            cPos[1] += getProp('border-top-width');

            cPos[0] += getProp('padding-left');
            cPos[1] += getProp('padding-top');

            pCont = this.containerObj;
        }

        // add border width
        cPos[0] += getProp('border-left-width');
        cPos[1] += getProp('border-top-width');

        // vml seems to ignore paddings
        if (this.renderer.type !== 'vml') {
            // add padding
            cPos[0] += getProp('padding-left');
            cPos[1] += getProp('padding-top');
        }

        this.cPos = cPos;

        return cPos;
    },

    /**
     * Get the position of the mouse in screen coordinates, relative to the upper left corner
     * of the host tag.
     * @param {Event} e Event object given by the browser.
     * @param {Number} [i] Only use in case of touch events. This determines which finger to use and should not be set
     * for mouseevents.
     * @returns {Array} Contains the mouse coordinates in user coordinates, ready  for {@link JXG.Coords}
     */
    getMousePosition: function (e, i) {
        var cPos = this.getCoordsTopLeftCorner(),
            absPos,
            v;

        // This fixes the object-drag bug on zoomed webpages on Android powered devices with the default WebKit browser
        // Seems to be obsolete now
        //if (JXG.isWebkitAndroid()) {
        //    cPos[0] -= document.body.scrollLeft;
        //    cPos[1] -= document.body.scrollTop;
        //}

        // position of mouse cursor relative to containers position of container
        absPos = JXG.getPosition(e, i);

        /*
        v = [1, absPos[0], absPos[1]];
        v = JXG.Math.matVecMult(this.cssTransMat, v);
        v[1] /= v[0];
        v[2] /= v[1];
        return [v[1]-cPos[0], v[2]-cPos[1]];
        */
        return [absPos[0] - cPos[0], absPos[1] - cPos[1]];
    },

    /**
     * Initiate moving the origin. This is used in mouseDown and touchStart listeners.
     * @param {Number} x Current mouse/touch coordinates
     * @param {Number} y Current mouse/touch coordinates
     */
    initMoveOrigin: function (x, y) {
        this.drag_dx = x - this.origin.scrCoords[1];
        this.drag_dy = y - this.origin.scrCoords[2];

        this.mode = this.BOARD_MODE_MOVE_ORIGIN;
    },

    /**
     * Collects all elements below the current mouse pointer and fulfilling the following constraints:
     * <ul><li>isDraggable</li><li>visible</li><li>not fixed</li><li>not frozen</li></ul>
     * @param {Number} x Current mouse/touch coordinates
     * @param {Number} y current mouse/touch coordinates
     * @param {Object} evt An event object
     * @param {String} type What type of event? 'touch' or 'mouse'.
     * @returns {Array} A list of geometric elements.
     */
    initMoveObject: function (x, y, evt, type) {
        var pEl, el, collect = [], haspoint, len = this.objectsList.length,
            dragEl = {visProp: {layer: -10000}};

        //for (el in this.objects) {
        for (el = 0; el < len; el++) {
            pEl = this.objectsList[el];
            haspoint = pEl.hasPoint && pEl.hasPoint(x, y);

            if (pEl.visProp.visible && haspoint) {
                pEl.triggerEventHandlers([type + 'down', 'down'], evt);
                this.downObjects.push(pEl);
            }
            if (((this.geonextCompatibilityMode &&
                    (pEl.elementClass === JXG.OBJECT_CLASS_POINT || pEl.type === JXG.OBJECT_TYPE_TEXT)) ||
                    !this.geonextCompatibilityMode) &&
                    pEl.isDraggable &&
                    pEl.visProp.visible &&
                    (!pEl.visProp.fixed) && (!pEl.visProp.frozen) &&
                    haspoint) {
                // Elements in the highest layer get priority.
                if (pEl.visProp.layer >= dragEl.visProp.layer) {
                    // If an element and its label have the focus
                    // simultaneously, the element is taken
                    // this only works if we assume that every browser runs
                    // through this.objects in the right order, i.e. an element A
                    // added before element B turns up here before B does.
                    if (!JXG.exists(dragEl.label) || pEl !== dragEl.label.content) {
                        dragEl = pEl;
                        collect[0] = dragEl;

                        // we can't drop out of this loop because of the event handling system
                        //if (this.options.takeFirst) {
                        //    return collect;
                        //}
                    }
                }
            }
        }

        if (collect.length > 0) {
            this.mode = this.BOARD_MODE_DRAG;
        }

        if (this.options.takeFirst) {
            collect.length = 1;
        }

        return collect;
    },

    /**
     * Moves an object.
     * @param {Number} x Coordinate
     * @param {Number} y Coordinate
     * @param {Object} o The touch object that is dragged: {JXG.Board#mouse} or {JXG.Board#touches}.
     * @param {Object} evt The event object.
     * @param {String} type Mouse or touch event?
     */
    moveObject: function (x, y, o, evt, type) {
        var newPos = new JXG.Coords(JXG.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(x, y), this),
            drag = o.obj,
            oldCoords;

        if (drag.type !== JXG.OBJECT_TYPE_GLIDER) {
            if (!isNaN(o.targets[0].Xprev + o.targets[0].Yprev)) {
                drag.setPositionDirectly(JXG.COORDS_BY_SCREEN, newPos.scrCoords.slice(1), [o.targets[0].Xprev, o.targets[0].Yprev]);
            }
            // Remember the actual position for the next move event. Then we are able to
            // compute the difference vector.
            o.targets[0].Xprev = newPos.scrCoords[1];
            o.targets[0].Yprev = newPos.scrCoords[2];
            this.update(drag);
        } else if (drag.type === JXG.OBJECT_TYPE_GLIDER) {
            oldCoords = drag.coords;

            // First the new position of the glider is set to the new mouse position
            drag.setPositionDirectly(JXG.COORDS_BY_USER, newPos.usrCoords.slice(1));

            // Then, from this position we compute the projection to the object the glider on which the glider lives.
            if (drag.slideObject.elementClass === JXG.OBJECT_CLASS_CIRCLE) {
                drag.coords = JXG.Math.Geometry.projectPointToCircle(drag, drag.slideObject, this);
            } else if (drag.slideObject.elementClass === JXG.OBJECT_CLASS_LINE) {
                drag.coords = JXG.Math.Geometry.projectPointToLine(drag, drag.slideObject, this);
            }

            // Now, we have to adjust the other group elements again.
            if (drag.group.length !== 0) {
                drag.group[drag.group.length - 1].dX = drag.coords.scrCoords[1] - oldCoords.scrCoords[1];
                drag.group[drag.group.length - 1].dY = drag.coords.scrCoords[2] - oldCoords.scrCoords[2];
                drag.group[drag.group.length - 1].update(this);
            } else {
                this.update(drag);
            }
        }

        drag.triggerEventHandlers([type + 'drag', 'drag'], evt);

        this.updateInfobox(drag);
        this.update();
        drag.highlight(true);
    },

    /**
     * Moves elements in multitouch mode.
     * @param {Array} p1 x,y coordinates of first touch
     * @param {Array} p2 x,y coordinates of second touch
     * @param {Object} o The touch object that is dragged: {JXG.Board#touches}.
     * @param {Object} evt The event object that lead to this movement.
     */
    twoFingerMove: function (p1, p2, o, evt) {
        var np1c, np2c, drag;

        if (JXG.exists(o) && JXG.exists(o.obj)) {
            drag = o.obj;
        } else {
            return;
        }

        // New finger position
        np1c = new JXG.Coords(JXG.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(p1[0], p1[1]), this);
        np2c = new JXG.Coords(JXG.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(p2[0], p2[1]), this);

        if (drag.elementClass === JXG.OBJECT_CLASS_LINE ||
                drag.type === JXG.OBJECT_TYPE_POLYGON) {
            this.twoFingerTouchObject(np1c, np2c, o, drag);
        } else if (drag.elementClass === JXG.OBJECT_CLASS_CIRCLE) {
            this.twoFingerTouchCircle(np1c, np2c, o, drag);
        }
        drag.triggerEventHandlers(['touchdrag', 'drag'], evt);

        o.targets[0].Xprev = np1c.scrCoords[1];
        o.targets[0].Yprev = np1c.scrCoords[2];
        o.targets[1].Xprev = np2c.scrCoords[1];
        o.targets[1].Yprev = np2c.scrCoords[2];
    },

    /**
     * Moves a line or polygon with two fingers
     * @param {JXG.Coords} np1c x,y coordinates of first touch
     * @param {JXG.Coords} np2c x,y coordinates of second touch
     * @param {object} o The touch object that is dragged: {JXG.Board#touches}.
     * @param {object} drag The object that is dragged:
     */
    twoFingerTouchObject: function (np1c, np2c, o, drag) {
        var np1, np2, op1, op2,
            nmid, omid, nd, od,
            d,
            S, alpha, t1, t2, t3, t4, t5;

        if (JXG.exists(o.targets[0]) &&
                JXG.exists(o.targets[1]) &&
                !isNaN(o.targets[0].Xprev + o.targets[0].Yprev + o.targets[1].Xprev + o.targets[1].Yprev)) {
            np1 = np1c.usrCoords;
            np2 = np2c.usrCoords;
            // Previous finger position
            op1 = (new JXG.Coords(JXG.COORDS_BY_SCREEN, [o.targets[0].Xprev, o.targets[0].Yprev], this)).usrCoords;
            op2 = (new JXG.Coords(JXG.COORDS_BY_SCREEN, [o.targets[1].Xprev, o.targets[1].Yprev], this)).usrCoords;

            // Affine mid points of the old and new positions
            omid = [1, (op1[1] + op2[1]) * 0.5, (op1[2] + op2[2]) * 0.5];
            nmid = [1, (np1[1] + np2[1]) * 0.5, (np1[2] + np2[2]) * 0.5];

            // Old and new directions
            od = JXG.Math.crossProduct(op1, op2);
            nd = JXG.Math.crossProduct(np1, np2);
            S = JXG.Math.crossProduct(od, nd);

            // If parallel, translate otherwise rotate
            if (Math.abs(S[0]) < JXG.Math.eps) {
                return;
                //t1 = this.create('transform', [nmid[1] - omid[1], nmid[2] - omid[2]], {type: 'translate'});
            }

            S[1] /= S[0];
            S[2] /= S[0];
            alpha = JXG.Math.Geometry.rad(omid.slice(1), S.slice(1), nmid.slice(1));
            t1 = this.create('transform', [alpha, S[1], S[2]], {type: 'rotate'});

            // Old midpoint of fingers after first transformation:
            t1.update();
            omid = JXG.Math.matVecMult(t1.matrix, omid);
            omid[1] /= omid[0];
            omid[2] /= omid[0];

            // Shift to the new mid point
            t2 = this.create('transform', [nmid[1] - omid[1], nmid[2] - omid[2]], {type: 'translate'});
            t2.update();
            //omid = JXG.Math.matVecMult(t2.matrix, omid);

            t1.melt(t2);
            if (drag.visProp.scalable) {
                // Scale
                d = JXG.Math.Geometry.distance(np1, np2) / JXG.Math.Geometry.distance(op1, op2);
                t3 = this.create('transform', [-nmid[1], -nmid[2]], {type: 'translate'});
                t4 = this.create('transform', [d, d], {type: 'scale'});
                t5 = this.create('transform', [nmid[1], nmid[2]], {type: 'translate'});
                t1.melt(t3).melt(t4).melt(t5);
            }

            if (drag.elementClass === JXG.OBJECT_CLASS_LINE) {
                t1.applyOnce([drag.point1, drag.point2]);
            } else if (drag.type === JXG.OBJECT_TYPE_POLYGON) {
                t1.applyOnce(drag.vertices.slice(0, -1));
            }

            this.update();
            drag.highlight(true);
        }
    },

    /*
     * Moves a circle with two fingers
     * @param {JXG.Coords} np1c x,y coordinates of first touch
     * @param {JXG.Coords} np2c x,y coordinates of second touch
     * @param {object} o The touch object that is dragged: {JXG.Board#touches}.
     * @param {object} drag The object that is dragged:
     */
    twoFingerTouchCircle: function (np1c, np2c, o, drag) {
        var np1, np2, op1, op2,
            d, alpha, t1, t2, t3, t4, t5;

        if (drag.method === 'pointCircle' ||
                drag.method === 'pointLine') {
            return;
        }

        if (JXG.exists(o.targets[0]) &&
                JXG.exists(o.targets[1]) &&
                !isNaN(o.targets[0].Xprev + o.targets[0].Yprev + o.targets[1].Xprev + o.targets[1].Yprev)) {

            np1 = np1c.usrCoords;
            np2 = np2c.usrCoords;
            // Previous finger position
            op1 = (new JXG.Coords(JXG.COORDS_BY_SCREEN, [o.targets[0].Xprev, o.targets[0].Yprev], this)).usrCoords;
            op2 = (new JXG.Coords(JXG.COORDS_BY_SCREEN, [o.targets[1].Xprev, o.targets[1].Yprev], this)).usrCoords;

            // Shift by the movement of the first finger
            t1 = this.create('transform', [np1[1] - op1[1], np1[2] - op1[2]], {type: 'translate'});
            alpha = JXG.Math.Geometry.rad(op2.slice(1), np1.slice(1), np2.slice(1));

            // Rotate and scale by the movement of the second finger
            t2 = this.create('transform', [-np1[1], -np1[2]], {type: 'translate'});
            t3 = this.create('transform', [alpha], {type: 'rotate'});
            t1.melt(t2).melt(t3);

            if (drag.visProp.scalable) {
                d = JXG.Math.Geometry.distance(np1, np2) / JXG.Math.Geometry.distance(op1, op2);
                t4 = this.create('transform', [d, d], {type: 'scale'});
                t1.melt(t4);
            }
            t5 = this.create('transform', [ np1[1], np1[2]], {type: 'translate'});
            t1.melt(t5);

            t1.applyOnce([drag.center]);

            if (drag.method === 'twoPoints') {
                t1.applyOnce([drag.point2]);
            } else if (drag.method === 'pointRadius') {
                if (JXG.isNumber(drag.updateRadius.origin)) {
                    drag.setRadius(drag.radius * d);
                }
            }
            this.update(drag.center);
            drag.highlight(true);
        }
    },

    highlightElements: function (x, y, evt, target) {
        var el, pEl, pId, len = this.objectsList.length;

        // Elements  below the mouse pointer which are not highlighted yet will be highlighted.
        for (el = 0; el < len; el++) {
            pEl = this.objectsList[el];
            pId = pEl.id;
            if (pEl.visProp.highlight && JXG.exists(pEl.hasPoint) && pEl.visProp.visible && pEl.hasPoint(x, y)) {
                // this is required in any case because otherwise the box won't be shown until the point is dragged
                this.updateInfobox(pEl);

                if (!JXG.exists(this.highlightedObjects[pId])) { // highlight only if not highlighted
                    this.highlightedObjects[pId] = pEl;
                    pEl.highlight();
                    this.triggerEventHandlers(['mousehit', 'hit'], evt, pEl, target);
                }

                if (pEl.mouseover) {
                    pEl.triggerEventHandlers(['mousemove', 'move'], evt);
                } else {
                    pEl.triggerEventHandlers(['mouseover', 'over'], evt);
                    pEl.mouseover = true;
                }
            }
        }

        for (el = 0; el < len; el++) {
            pEl = this.objectsList[el];
            pId = pEl.id;
            if (pEl.mouseover) {
                if (!this.highlightedObjects[pId]) {
                    pEl.triggerEventHandlers(['mouseout', 'out'], evt);
                    pEl.mouseover = false;
                }
            }
        }
    },

    /**
     * Helper function which returns a reasonable starting point for the object being dragged.
     * Formerly known as initXYstart().
     * @private
     * @param {JXG.GeometryElement} obj The object to be dragged
     * @param {Array} targets Array of targets. It is changed by this function.
     */
    saveStartPos: function (obj, targets) {
        var xy = [], i, len;

        if (obj.elementClass === JXG.OBJECT_CLASS_LINE) {
            xy.push(obj.point1.coords.usrCoords);
            xy.push(obj.point2.coords.usrCoords);
        } else if (obj.elementClass === JXG.OBJECT_CLASS_CIRCLE) {
            xy.push(obj.center.coords.usrCoords);
        } else if (obj.type === JXG.OBJECT_TYPE_GLIDER) {
            xy.push([obj.position, obj.position, obj.position]);
        } else if (obj.type === JXG.OBJECT_TYPE_POLYGON) {
            len = obj.vertices.length - 1;
            for (i = 0; i < len; i++) {
                xy.push(obj.vertices[i].coords.usrCoords);
            }
        } else if (obj.elementClass === JXG.OBJECT_CLASS_POINT) {
            xy.push(obj.coords.usrCoords);
        } else {
            try {
                xy.push(obj.coords.usrCoords);
            } catch (e) {
                JXG.debug('JSXGraph+ saveStartPos: obj.coords.usrCoords not available: ' + e);
            }
        }

        len = xy.length;
        for (i = 0; i < len; i++) {
            targets.Zstart.push(xy[i][0]);
            targets.Xstart.push(xy[i][1]);
            targets.Ystart.push(xy[i][2]);
        }
    },

    mouseOriginMoveStart: function (evt) {
        var r = this.options.pan.enabled && (!this.options.pan.needShift || evt.shiftKey),
            pos;

        if (r) {
            pos = this.getMousePosition(evt);
            this.initMoveOrigin(pos[0], pos[1]);
        }

        return r;
    },

    mouseOriginMove: function (evt) {
        var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN),
            pos;

        if (r) {
            pos = this.getMousePosition(evt);
            this.moveOrigin(pos[0], pos[1], true);
        }

        return r;
    },

    touchOriginMoveStart: function (evt) {
        var touches = evt[JXG.touchProperty],
            twoFingersCondition = (touches.length === 2 && JXG.Math.Geometry.distance([touches[0].screenX, touches[0].screenY], [touches[1].screenX, touches[1].screenY]) < 80),
            r = this.options.pan.enabled && (!this.options.pan.needTwoFingers || twoFingersCondition),
            pos;

        if (r) {
            pos = this.getMousePosition(evt, 0);
            this.initMoveOrigin(pos[0], pos[1]);
        }

        return r;
    },

    touchOriginMove: function (evt) {
        var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN),
            pos;

        if (r) {
            pos = this.getMousePosition(evt, 0);
            this.moveOrigin(pos[0], pos[1], true);
        }

        return r;
    },

    originMoveEnd: function () {
        this.mode = this.BOARD_MODE_NONE;
    },

    /**********************************************************
     *
     * Event Handler
     *
     **********************************************************/

    /**
     *  Add all possible event handlers to the board object
     */
    addEventHandlers: function () {
        this.addMouseEventHandlers();
        this.addTouchEventHandlers();
    },

    addMouseEventHandlers: function () {
        if (!this.hasMouseHandlers && JXG.isBrowser) {
            JXG.addEvent(this.containerObj, 'mousedown', this.mouseDownListener, this);
            JXG.addEvent(this.containerObj, 'mousemove', this.mouseMoveListener, this);

            JXG.addEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this);
            JXG.addEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this);

            this.hasMouseHandlers = true;

            // This one produces errors on IE
            //   JXG.addEvent(this.containerObj, 'contextmenu', function (e) { e.preventDefault(); return false;}, this);

            // This one works on IE, Firefox and Chromium with default configurations. On some Safari
            // or Opera versions the user must explicitly allow the deactivation of the context menu.
            this.containerObj.oncontextmenu = function (e) {
                if (JXG.exists(e)) {
                    e.preventDefault();
                }

                return false;
            };
        }
    },

    addTouchEventHandlers: function () {
		if (!this.hasTouchHandlers && JXG.isBrowser) {
            JXG.addEvent(this.containerObj, 'touchstart', this.touchStartListener, this);
            JXG.addEvent(this.containerObj, 'touchmove', this.touchMoveListener, this);

            JXG.addEvent(this.containerObj, 'gesturestart', this.gestureStartListener, this);
            JXG.addEvent(this.containerObj, 'gesturechange', this.gestureChangeListener, this);

            this.hasTouchHandlers = true;
        }
    },

    removeMouseEventHandlers: function () {
        if (this.hasMouseHandlers && JXG.isBrowser) {
            JXG.removeEvent(this.containerObj, 'mousedown', this.mouseDownListener, this);
            JXG.removeEvent(this.containerObj, 'mousemove', this.mouseMoveListener, this);

            if (this.hasMouseUp) {
                JXG.removeEvent(document, 'mouseup', this.mouseUpListener, this);
                this.hasMouseUp = false;
            }

            JXG.removeEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this);
            JXG.removeEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this);

            this.hasMouseHandlers = false;
        }
    },

    removeTouchEventHandlers: function () {
        if (this.hasTouchHandlers && JXG.isBrowser) {
            JXG.removeEvent(this.containerObj, 'touchstart', this.touchStartListener, this);
            JXG.removeEvent(this.containerObj, 'touchmove', this.touchMoveListener, this);

            if (this.hasTouchEnd) {
                JXG.removeEvent(document, 'touchend', this.touchEndListener, this);
                this.hasTouchEnd = false;
            }

			JXG.removeEvent(this.containerObj, 'gesturestart', this.gestureStartListener, this);
			JXG.removeEvent(this.containerObj, 'gesturechange', this.gestureChangeListener, this);

            this.hasTouchHandlers = false;
        }
    },

    /**
     * Remove all event handlers from the board object
     */
    removeEventHandlers: function () {
        this.removeMouseEventHandlers();
        this.removeTouchEventHandlers();
    },

    /**
     * Handler for click on left arrow in the navigation bar
     * @private
     */
    clickLeftArrow: function () {
        this.moveOrigin(this.origin.scrCoords[1] + this.canvasWidth * 0.1, this.origin.scrCoords[2]);
        return this;
    },

    /**
     * Handler for click on right arrow in the navigation bar
     * @private
     */
    clickRightArrow: function () {
        this.moveOrigin(this.origin.scrCoords[1] - this.canvasWidth * 0.1, this.origin.scrCoords[2]);
        return this;
    },

    /**
     * Handler for click on up arrow in the navigation bar
     * @private
     */
    clickUpArrow: function () {
        this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] - this.canvasHeight * 0.1);
        return this;
    },

    /**
     * Handler for click on down arrow in the navigation bar
     * @private
     */
    clickDownArrow: function () {
        this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] + this.canvasHeight * 0.1);
        return this;
    },

    /**
     * Triggered on iOS/Safari while the user inputs a gesture (e.g. pinch) and is used to zoom into the board. Only works on iOS/Safari.
     * @param {Event} evt Browser event object
     * @return {Boolean}
     */
    gestureChangeListener: function (evt) {
        var c,
            zx = this.options.zoom.factorX,
            zy = this.options.zoom.factorY;

        if (!this.options.zoom.wheel) {
            return true;
        }

        evt.preventDefault();

        if (this.mode === this.BOARD_MODE_NONE) {
            c = new JXG.Coords(JXG.COORDS_BY_SCREEN, this.getMousePosition(evt), this);

            this.options.zoom.factorX = evt.scale / this.prevScale;
            this.options.zoom.factorY = evt.scale / this.prevScale;

            this.zoomIn(c.usrCoords[1], c.usrCoords[2]);
            this.prevScale = evt.scale;

            this.options.zoom.factorX = zx;
            this.options.zoom.factorY = zy;
        }

        return false;
    },

    /**
     * Called by iOS/Safari as soon as the user starts a gesture (only works on iOS/Safari).
     * @param {Event} evt
     * @return {Boolean}
     */
    gestureStartListener: function (evt) {
        if (!this.options.zoom.wheel) {
            return true;
        }

        evt.preventDefault();
        this.prevScale = 1;

        return false;
    },

    /**
     * Touch-Events
     */

    /**
     * This method is called by the browser when a finger touches the surface of the touch-device.
     * @param {Event} evt The browsers event object.
     * @param {Object} object If the object to be dragged is already known, it can be submitted via this parameter
     * @returns {Boolean} ...
     */
    touchStartListener: function (evt, object) {
        var i, pos, elements, j, k, time,
            eps = this.options.precision.touch,
            obj, found, targets,
            evtTouches = evt[JXG.touchProperty],
            target;

        if (!this.hasTouchEnd) {
            JXG.addEvent(document, 'touchend', this.touchEndListener, this);
            this.hasTouchEnd = true;
        }

        if (this.hasMouseHandlers) {
			this.removeMouseEventHandlers();
        }

        // prevent accidental selection of text
        if (document.selection && typeof document.selection.empty === 'function') {
            document.selection.empty();
        } else if (window.getSelection) {
            window.getSelection().removeAllRanges();
        }

        // multitouch
        this.options.precision.hasPoint = this.options.precision.touch;

        // this is the most critical part. first we should run through the existing touches and collect all targettouches that don't belong to our
        // previous touches. once this is done we run through the existing touches again and watch out for free touches that can be attached to our existing
        // touches, e.g. we translate (parallel translation) a line with one finger, now a second finger is over this line. this should change the operation to
        // a rotational translation. or one finger moves a circle, a second finger can be attached to the circle: this now changes the operation from translation to
        // stretching. as a last step we're going through the rest of the targettouches and initiate new move operations:
        //  * points have higher priority over other elements.
        //  * if we find a targettouch over an element that could be transformed with more than one finger, we search the rest of the targettouches, if they are over
        //    this element and add them.
        // ADDENDUM 11/10/11:
        //  (1) run through the touches control object,
        //  (2) try to find the targetTouches for every touch. on touchstart only new touches are added, hence we can find a targettouch
        //      for every target in our touches objects
        //  (3) if one of the targettouches was bound to a touches targets array, mark it
        //  (4) run through the targettouches. if the targettouch is marked, continue. otherwise check for elements below the targettouch:
        //      (a) if no element could be found: mark the target touches and continue
        //      --- in the following cases, "init" means:
        //           (i) check if the element is already used in another touches element, if so, mark the targettouch and continue
        //          (ii) if not, init a new touches element, add the targettouch to the touches property and mark it
        //      (b) if the element is a point, init
        //      (c) if the element is a line, init and try to find a second targettouch on that line. if a second one is found, add and mark it
        //      (d) if the element is a circle, init and try to find TWO other targettouches on that circle. if only one is found, mark it and continue. otherwise
        //          add both to the touches array and mark them.
        for (i = 0; i < evtTouches.length; i++) {
            evtTouches[i].jxg_isused = false;
        }

        for (i = 0; i < this.touches.length; i++) {
            for (j = 0; j < this.touches[i].targets.length; j++) {
                this.touches[i].targets[j].num = -1;
                eps = this.options.precision.touch;

                do {
                    for (k = 0; k < evtTouches.length; k++) {
                        // find the new targettouches
                        if (Math.abs(Math.pow(evtTouches[k].screenX - this.touches[i].targets[j].X, 2) +
                                Math.pow(evtTouches[k].screenY - this.touches[i].targets[j].Y, 2)) < eps * eps) {
                            this.touches[i].targets[j].num = k;

                            this.touches[i].targets[j].X = evtTouches[k].screenX;
                            this.touches[i].targets[j].Y = evtTouches[k].screenY;
                            evtTouches[k].jxg_isused = true;
                            break;
                        }
                    }

                    eps *= 2;

                } while (this.touches[i].targets[j].num === -1 && eps < this.options.precision.touchMax);

                if (this.touches[i].targets[j].num === -1) {
                    JXG.debug('i couldn\'t find a targettouches for target no ' + j + ' on ' + this.touches[i].obj.name + ' (' + this.touches[i].obj.id + '). Removed the target.');
                    JXG.debug('eps = ' + eps + ', touchMax = ' + JXG.Options.precision.touchMax);
                    this.touches[i].targets.splice(i, 1);
                }

            }
        }

        // we just re-mapped the targettouches to our existing touches list. now we have to initialize some touches from additional targettouches
        for (i = 0; i < evtTouches.length; i++) {
            if (object || !evtTouches[i].jxg_isused) {
                pos = this.getMousePosition(evt, i);

                if (object) {
                    elements = [ object ];
                    this.mode = this.BOARD_MODE_DRAG;
                } else {
                    elements = this.initMoveObject(pos[0], pos[1], evt, 'touch');
                }

                if (elements.length !== 0) {
                    obj = elements[elements.length - 1];

                    if (JXG.isPoint(obj) || obj.type === JXG.OBJECT_TYPE_TEXT || obj.type === JXG.OBJECT_TYPE_TICKS) {
                        // it's a point, so it's single touch, so we just push it to our touches

                        targets = [{ num: i, X: evtTouches[i].screenX, Y: evtTouches[i].screenY, Xprev: NaN, Yprev: NaN, Xstart: [], Ystart: [], Zstart: [] }];

                        // For the UNDO/REDO of object moves
                        this.saveStartPos(obj, targets[0]);
                        this.touches.push({ obj: obj, targets: targets });
                        this.highlightedObjects[obj.id] = obj;
                        obj.highlight(true);
                    } else if (obj.elementClass === JXG.OBJECT_CLASS_LINE ||
                                    obj.elementClass === JXG.OBJECT_CLASS_CIRCLE ||
                                    obj.type === JXG.OBJECT_TYPE_POLYGON) {
                        found = false;

                        // first check if this geometric object is already capture in this.touches
                        for (j = 0; j < this.touches.length; j++) {
                            if (obj.id === this.touches[j].obj.id) {
                                found = true;
                                // only add it, if we don't have two targets in there already
                                if (this.touches[j].targets.length === 1) {
                                    target = { num: i, X: evtTouches[i].screenX, Y: evtTouches[i].screenY, Xprev: NaN, Yprev: NaN, Xstart: [], Ystart: [], Zstart: [] };

                                    // For the UNDO/REDO of object moves
                                    this.saveStartPos(obj, target);
                                    this.touches[j].targets.push(target);
                                }

                                evtTouches[i].jxg_isused = true;
                            }
                        }

                        // we couldn't find it in touches, so we just init a new touches
                        // IF there is a second touch targetting this line, we will find it later on, and then add it to
                        // the touches control object.
                        if (!found) {
                            targets = [{ num: i, X: evtTouches[i].screenX, Y: evtTouches[i].screenY, Xprev: NaN, Yprev: NaN, Xstart: [], Ystart: [], Zstart: [] }];

                            // For the UNDO/REDO of object moves
                            this.saveStartPos(obj, targets[0]);
                            this.touches.push({ obj: obj, targets: targets });
                            this.highlightedObjects[obj.id] = obj;
                            obj.highlight(true);
                        }
                    }
                }

                evtTouches[i].jxg_isused = true;
            }
        }

        if (this.touches.length > 0) {
            evt.preventDefault();
            evt.stopPropagation();
        }

        // move origin - but only if we're not in drag mode
        if (this.mode === this.BOARD_MODE_NONE && this.touchOriginMoveStart(evt)) {
            this.triggerEventHandlers(['touchstart', 'down'], evt);
            return false;
        }

        if (JXG.isWebkitAndroid()) {
            time = new Date();
            this.touchMoveLast = time.getTime() - 200;
        }

        this.options.precision.hasPoint = this.options.precision.mouse;

        this.triggerEventHandlers(['touchstart', 'down'], evt);

        return this.touches.length > 0;
    },

    /**
     * Called periodically by the browser while the user moves his fingers across the device.
     * @param {Event} evt
     * @return {Boolean}
     */
    touchMoveListener: function (evt) {
        var i, count = 0, pos,
            evtTouches = evt[JXG.touchProperty],
            time;

        if (this.mode !== this.BOARD_MODE_NONE) {
            evt.preventDefault();
            evt.stopPropagation();
        }

        // Reduce update frequency for Android devices
        if (JXG.isWebkitAndroid()) {
            time = new Date();
            time = time.getTime();

            if (time - this.touchMoveLast < 80) {
                this.updateQuality = this.BOARD_QUALITY_HIGH;
                this.triggerEventHandlers(['touchmove', 'move'], evt, this.mode);

                return false;
            }

            this.touchMoveLast = time;
        }

        if (this.mode !== this.BOARD_MODE_DRAG) {
            this.renderer.hide(this.infobox);
        }

        this.options.precision.hasPoint = this.options.precision.touch;

        if (!this.touchOriginMove(evt)) {

            if (this.mode === this.BOARD_MODE_DRAG) {
                // Runs over through all elements which are touched
                // by at least one finger.
                for (i = 0; i < this.touches.length; i++) {
                    // Touch by one finger:  this is possible for all elements that can be dragged
                    if (this.touches[i].targets.length === 1) {
                        if (evtTouches[this.touches[i].targets[0].num]) {
                            this.touches[i].targets[0].X = evtTouches[this.touches[i].targets[0].num].screenX;
                            this.touches[i].targets[0].Y = evtTouches[this.touches[i].targets[0].num].screenY;
                            pos = this.getMousePosition(evt, this.touches[i].targets[0].num);
                            this.moveObject(pos[0], pos[1], this.touches[i], evt, 'touch');
                        }
                        // Touch by two fingers: moving lines
                    } else if (this.touches[i].targets.length === 2 && this.touches[i].targets[0].num > -1 && this.touches[i].targets[1].num > -1) {
                        if (evtTouches[this.touches[i].targets[0].num] && evtTouches[this.touches[i].targets[1].num]) {
                            this.touches[i].targets[0].X = evtTouches[this.touches[i].targets[0].num].screenX;
                            this.touches[i].targets[0].Y = evtTouches[this.touches[i].targets[0].num].screenY;
                            this.touches[i].targets[1].X = evtTouches[this.touches[i].targets[1].num].screenX;
                            this.touches[i].targets[1].Y = evtTouches[this.touches[i].targets[1].num].screenY;
                            this.twoFingerMove(
                                this.getMousePosition(evt, this.touches[i].targets[0].num),
                                this.getMousePosition(evt, this.touches[i].targets[1].num),
                                this.touches[i],
                                evt
                            );
                        }
                    }
                }
            }
        }

        if (this.mode !== this.BOARD_MODE_DRAG) {
            this.renderer.hide(this.infobox);
        }

        this.options.precision.hasPoint = this.options.precision.mouse;
        this.triggerEventHandlers(['touchmove', 'move'], evt, this.mode);

        return this.mode === this.BOARD_MODE_NONE;
    },

    /**
     * Triggered as soon as the user stops touching the device with at least one finger.
     * @param {Event} evt
     * @return {Boolean}
     */
    touchEndListener: function (evt) {
        var i, j, k,
            eps = this.options.precision.touch,
            tmpTouches = [], found, foundNumber,
            evtTouches = evt[JXG.touchProperty];

        this.triggerEventHandlers(['touchend', 'up'], evt);
        this.renderer.hide(this.infobox);

        if (evtTouches.length > 0) {
            for (i = 0; i < this.touches.length; i++) {
                tmpTouches[i] = this.touches[i];
            }
            this.touches.length = 0;

            // try to convert the operation, e.g. if a lines is rotated and translated with two fingers and one finger is lifted,
            // convert the operation to a simple one-finger-translation.
            // ADDENDUM 11/10/11:
            // see addendum to touchStartListener from 11/10/11
            // (1) run through the tmptouches
            // (2) check the touches.obj, if it is a
            //     (a) point, try to find the targettouch, if found keep it and mark the targettouch, else drop the touch.
            //     (b) line with
            //          (i) one target: try to find it, if found keep it mark the targettouch, else drop the touch.
            //         (ii) two targets: if none can be found, drop the touch. if one can be found, remove the other target. mark all found targettouches
            //     (c) circle with [proceed like in line]

            // init the targettouches marker
            for (i = 0; i < evtTouches.length; i++) {
                evtTouches[i].jxg_isused = false;
            }

            for (i = 0; i < tmpTouches.length; i++) {
                // could all targets of the current this.touches.obj be assigned to targettouches?
                found = false;
                foundNumber = 0;

                for (j = 0; j < tmpTouches[i].targets.length; j++) {
                    tmpTouches[i].targets[j].found = false;
                    for (k = 0; k < evtTouches.length; k++) {
                        if (Math.abs(Math.pow(evtTouches[k].screenX - tmpTouches[i].targets[j].X, 2) + Math.pow(evtTouches[k].screenY - tmpTouches[i].targets[j].Y, 2)) < eps * eps) {
                            tmpTouches[i].targets[j].found = true;
                            tmpTouches[i].targets[j].num = k;
                            tmpTouches[i].targets[j].X = evtTouches[k].screenX;
                            tmpTouches[i].targets[j].Y = evtTouches[k].screenY;
                            foundNumber++;
                            break;
                        }
                    }
                }

                if (JXG.isPoint(tmpTouches[i].obj)) {
                    found = (tmpTouches[i].targets[0] && tmpTouches[i].targets[0].found);
                } else if (tmpTouches[i].obj.elementClass === JXG.OBJECT_CLASS_LINE) {
                    found = (tmpTouches[i].targets[0] && tmpTouches[i].targets[0].found) || (tmpTouches[i].targets[1] && tmpTouches[i].targets[1].found);
                } else if (tmpTouches[i].obj.elementClass === JXG.OBJECT_CLASS_CIRCLE) {
                    found = foundNumber === 1 || foundNumber === 3;
                }

                // if we found this object to be still dragged by the user, add it back to this.touches
                if (found) {
                    this.touches.push({
                        obj: tmpTouches[i].obj,
                        targets: []
                    });

                    for (j = 0; j < tmpTouches[i].targets.length; j++) {
                        if (tmpTouches[i].targets[j].found) {
                            this.touches[this.touches.length - 1].targets.push({
                                num: tmpTouches[i].targets[j].num,
                                X: tmpTouches[i].targets[j].screenX,
                                Y: tmpTouches[i].targets[j].screenY,
                                Xprev: NaN,
                                Yprev: NaN,
                                Xstart: tmpTouches[i].targets[j].Xstart,
                                Ystart: tmpTouches[i].targets[j].Ystart,
                                Zstart: tmpTouches[i].targets[j].Zstart
                            });
                        }
                    }

                } else {
                    delete this.highlightedObjects[tmpTouches[i].obj.id];
                    tmpTouches[i].obj.noHighlight();
                }
            }

        } else {
            this.touches.length = 0;
        }

        for (i = 0; i < this.downObjects.length; i++) {
            found = false;
            for (j = 0; j < this.touches.length; j++) {
                if (this.touches[j].obj.id === this.downObjects[i].id) {
                    found = true;
                }
            }
            if (!found) {
                this.downObjects[i].triggerEventHandlers(['touchup', 'up'], evt);
                this.downObjects[i].snapToGrid();
                this.downObjects.splice(i, 1);
            }
        }

        if (!evtTouches || evtTouches.length === 0) {
            JXG.removeEvent(document, 'touchend', this.touchEndListener, this);
            this.hasTouchEnd = false;

            this.dehighlightAll();
            this.updateQuality = this.BOARD_QUALITY_HIGH;

            this.originMoveEnd();
            this.update();
        }

        return true;
    },

    /**
     * This method is called by the browser when the mouse button is clicked.
     * @param {Event} evt The browsers event object.
     * @param {Object} object If the object to be dragged is already known, it can be submitted via this parameter
     * @returns {Boolean} True if no element is found under the current mouse pointer, false otherwise.
     */
    mouseDownListener: function (evt, object) {
        var pos, elements, xy, result, i;

        // prevent accidental selection of text
        if (document.selection && typeof document.selection.empty === 'function') {
            document.selection.empty();
        } else if (window.getSelection) {
            window.getSelection().removeAllRanges();
        }

        if (!this.hasMouseUp) {
            JXG.addEvent(document, 'mouseup', this.mouseUpListener, this);
            this.hasMouseUp = true;
        }

        pos = this.getMousePosition(evt);

        if (object) {
            elements = [ object ];
            this.mode = this.BOARD_MODE_DRAG;
        } else {
            elements = this.initMoveObject(pos[0], pos[1], evt, 'mouse');
        }

        // if no draggable object can be found, get out here immediately
        if (elements.length === 0) {
            this.mode = this.BOARD_MODE_NONE;
            result = true;
        } else {
            this.mouse = {
                obj: null,
                targets: [{
                    X: pos[0],
                    Y: pos[1],
                    Xprev: NaN,
                    Yprev: NaN
                }]
            };
            this.mouse.obj = elements[elements.length - 1];

            this.dehighlightAll();
            this.highlightedObjects[this.mouse.obj.id] = this.mouse.obj;
            this.mouse.obj.highlight(true);

            this.mouse.targets[0].Xstart = [];
            this.mouse.targets[0].Ystart = [];
            this.mouse.targets[0].Zstart = [];

            this.saveStartPos(this.mouse.obj, this.mouse.targets[0]);

            // prevent accidental text selection
            // this could get us new trouble: input fields, links and drop down boxes placed as text
            // on the board don't work anymore.
            if (evt && evt.preventDefault) {
                evt.preventDefault();
            } else if (window.event) {
                window.event.returnValue = false;
            }
        }

        if (this.mode === this.BOARD_MODE_NONE) {
            result = this.mouseOriginMoveStart(evt);
        }

        if (!object) {
            this.triggerEventHandlers(['mousedown', 'down'], evt);
        }

        return result;
    },

    /**
     * This method is called by the browser when the mouse button is released.
     * @param {Event} evt
     */
    mouseUpListener: function (evt) {
        var i;

        this.triggerEventHandlers(['mouseup', 'up'], evt);

        // redraw with high precision
        this.updateQuality = this.BOARD_QUALITY_HIGH;

        if (this.mouse && this.mouse.obj) {
            this.mouse.obj.snapToGrid();
        }

        this.originMoveEnd();
        this.dehighlightAll();
        this.update();

        for (i = 0; i < this.downObjects.length; i++) {
            this.downObjects[i].triggerEventHandlers(['mouseup', 'up'], evt);
        }

        this.downObjects.length = 0;

        if (this.hasMouseUp) {
            JXG.removeEvent(document, 'mouseup', this.mouseUpListener, this);
            this.hasMouseUp = false;
        }

        // release dragged mouse object
        this.mouse = null;
    },

    /**
     * This method is called by the browser when the mouse is moved.
     * @param {Event} evt The browsers event object.
     */
    mouseMoveListener: function (evt) {
        var pos;

        pos = this.getMousePosition(evt);

        this.updateQuality = this.BOARD_QUALITY_LOW;

        if (this.mode !== this.BOARD_MODE_DRAG) {
            this.dehighlightAll();
            this.renderer.hide(this.infobox);
        }

        // we have to check for three cases:
        //   * user moves origin
        //   * user drags an object
        //   * user just moves the mouse, here highlight all elements at
        //     the current mouse position

        if (!this.mouseOriginMove(evt)) {
            if (this.mode === this.BOARD_MODE_DRAG) {
                this.moveObject(pos[0], pos[1], this.mouse, evt, 'mouse');
            } else { // BOARD_MODE_NONE
                this.highlightElements(pos[0], pos[1], evt, -1);
            }
        }

        this.updateQuality = this.BOARD_QUALITY_HIGH;

        this.triggerEventHandlers(['mousemove', 'move'], evt, this.mode);
    },

    /**
     * Handler for mouse wheel events. Used to zoom in and out of the board.
     * @param {Event} evt
     * @returns {Boolean}
     */
    mouseWheelListener: function (evt) {
        if (!this.options.zoom.wheel || (this.options.zoom.needShift && !evt.shiftKey)) {
            return true;
        }

        evt = evt || window.event;
        var wd = evt.detail ? -evt.detail : evt.wheelDelta / 40,
            pos = new JXG.Coords(JXG.COORDS_BY_SCREEN, this.getMousePosition(evt), this);

        if (wd > 0) {
            this.zoomIn(pos.usrCoords[1], pos.usrCoords[2]);
        } else {
            this.zoomOut(pos.usrCoords[1], pos.usrCoords[2]);
        }

        evt.preventDefault();
        return false;
    },

    /**********************************************************
     *
     * End of Event Handlers
     *
     **********************************************************/

    /**
     * Updates and displays a little info box to show coordinates of current selected points.
     * @param {JXG.GeometryElement} el A GeometryElement
     * @returns {JXG.Board} Reference to the board
     */
    updateInfobox: function (el) {
        var x, y, xc, yc;

        if (!el.visProp.showinfobox) {
            return this;
        }
        if (el.elementClass === JXG.OBJECT_CLASS_POINT) {
            xc = el.coords.usrCoords[1];
            yc = el.coords.usrCoords[2];

            this.infobox.setCoords(xc + this.infobox.distanceX / this.unitX, yc + this.infobox.distanceY / this.unitY);

            if (typeof el.infoboxText !== 'string') {
                if (el.visProp.infoboxdigits === 'auto') {
                    x = JXG.autoDigits(xc);
                    y = JXG.autoDigits(yc);
                } else if (JXG.isNumber(el.visProp.infoboxdigits)) {
                    x = xc.toFixed(el.visProp.infoboxdigits);
                    y = yc.toFixed(el.visProp.infoboxdigits);
                } else {
                    x = xc;
                    y = yc;
                }

                this.highlightInfobox(x, y, el);
            } else {
                this.highlightCustomInfobox(el.infoboxText, el);
            }

            this.renderer.show(this.infobox);
        }
        return this;
    },

    /**
     * Changes the text of the info box to what is provided via text.
     * @param {String} text
     * @returns {JXG.Board} Reference to the board.
     */
    highlightCustomInfobox: function (text) {
        this.infobox.setText(text);
        return this;
    },

    /**
     * Changes the text of the info box to show the given coordinates.
     * @param {Number} x
     * @param {Number} y
     * @param {JXG.Point} el The element the mouse is pointing at
     * @returns {JXG.Board} Reference to the board.
     */
    highlightInfobox: function (x, y, el) {
        this.highlightCustomInfobox('(' + x + ', ' + y + ')');
        return this;
    },

    /**
     * Remove highlighting of all elements.
     * @returns {JXG.Board} Reference to the board.
     */
    dehighlightAll: function () {
        var el, pEl, needsDehighlight = false;

        for (el in this.highlightedObjects) {
            if (this.highlightedObjects.hasOwnProperty(el)) {
                pEl = this.highlightedObjects[el];

                if (this.hasMouseHandlers) {
                    pEl.noHighlight();
                }

                needsDehighlight = true;

                // In highlightedObjects should only be objects which fulfill all these conditions
                // And in case of complex elements, like a turtle based fractal, it should be faster to
                // just de-highlight the element instead of checking hasPoint...
                // if ((!JXG.exists(pEl.hasPoint)) || !pEl.hasPoint(x, y) || !pEl.visProp.visible)
            }
        }

        this.highlightedObjects = {};

        // We do not need to redraw during dehighlighting in CanvasRenderer
        // because we are redrawing anyhow
        //  -- We do need to redraw during dehighlighting. Otherwise objects won't be dehighlighted until
        // another object is highlighted.
        if (this.options.renderer === 'canvas' && needsDehighlight) {
            this.prepareUpdate();
            this.renderer.suspendRedraw(this);
            this.updateRenderer();
            this.renderer.unsuspendRedraw();
        }

        return this;
    },

    /**
     * Returns the input parameters in an array. This method looks pointless and it really is, but it had a purpose
     * once.
     * @param {Number} x X coordinate in screen coordinates
     * @param {Number} y Y coordinate in screen coordinates
     * @returns {Array} Coordinates of the mouse in screen coordinates.
     */
    getScrCoordsOfMouse: function (x, y) {
        return [x, y];
    },

    /**
     * This method calculates the user coords of the current mouse coordinates.
     * @param {Event} evt Event object containing the mouse coordinates.
     * @returns {Array} Coordinates of the mouse in screen coordinates.
     */
    getUsrCoordsOfMouse: function (evt) {
        var cPos = this.getCoordsTopLeftCorner(),
            absPos = JXG.getPosition(evt),
            x = absPos[0] - cPos[0],
            y = absPos[1] - cPos[1],
            newCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x, y], this);

        return newCoords.usrCoords.slice(1);
    },

    /**
     * Collects all elements under current mouse position plus current user coordinates of mouse cursor.
     * @param {Event} evt Event object containing the mouse coordinates.
     * @returns {Array} Array of elements at the current mouse position plus current user coordinates of mouse.
     */
    getAllUnderMouse: function (evt) {
        var elList = this.getAllObjectsUnderMouse(evt);
        elList.push(this.getUsrCoordsOfMouse(evt));

        return elList;
    },

    /**
     * Collects all elements under current mouse position.
     * @param {Event} evt Event object containing the mouse coordinates.
     * @returns {Array} Array of elements at the current mouse position.
     */
    getAllObjectsUnderMouse: function (evt) {
        var cPos = this.getCoordsTopLeftCorner(),
            absPos = JXG.getPosition(evt),
            dx = absPos[0] - cPos[0],
            dy = absPos[1] - cPos[1],
            elList = [],
            el,
            pEl,
            len = this.objectsList.length;

        for (el = 0; el < len; el++) {
            pEl = this.objectsList[el];
            if (pEl.visProp.visible && pEl.hasPoint && pEl.hasPoint(dx, dy)) {
                elList[elList.length] = pEl;
            }
        }

        return elList;
    },

    /**
     * Moves the origin and initializes an update of all elements.
     * @param {Number} x
     * @param {Number} y
     * @param {Boolean} [diff=false]
     * @returns {JXG.Board} Reference to this board.
     */
    moveOrigin: function (x, y, diff) {
        var el, ob, len = this.objectsList.length;

        if (JXG.exists(x) && JXG.exists(y)) {
            this.origin.scrCoords[1] = x;
            this.origin.scrCoords[2] = y;

            if (diff) {
                this.origin.scrCoords[1] -= this.drag_dx;
                this.origin.scrCoords[2] -= this.drag_dy;
            }
        }

        for (ob = 0; ob < len; ob++) {
            el = this.objectsList[ob];
            if (!el.visProp.frozen && (el.elementClass === JXG.OBJECT_CLASS_POINT ||
                    el.elementClass === JXG.OBJECT_CLASS_CURVE ||
                    el.type === JXG.OBJECT_TYPE_AXIS ||
                    el.type === JXG.OBJECT_TYPE_TEXT)) {
                if (el.elementClass !== JXG.OBJECT_CLASS_CURVE && el.type !== JXG.OBJECT_TYPE_AXIS) {
                    el.coords.usr2screen();
                }
            }
        }

        this.clearTraces();
        this.fullUpdate();

        return this;
    },

    /**
     * Add conditional updates to the elements.
     * @param {String} str String containing coniditional update in geonext syntax
     */
    addConditions: function (str) {
        var term, m, left, right, name, el, property,
            plaintext = 'var el, x, y, c, rgbo;\n',
            i = str.indexOf('<data>'),
            j = str.indexOf('<' + '/data>');

        if (i < 0) {
            return;
        }

        while (i >= 0) {
            term = str.slice(i + 6, j);   // throw away <data>
            m = term.indexOf('=');
            left = term.slice(0, m);
            right = term.slice(m + 1);
            m = left.indexOf('.');     // Dies erzeugt Probleme bei Variablennamen der Form " Steuern akt."
            name = left.slice(0, m);    //.replace(/\s+$/,''); // do NOT cut out name (with whitespace)
            el = this.elementsByName[JXG.unescapeHTML(name)];

            property = left.slice(m + 1).replace(/\s+/g, '').toLowerCase(); // remove whitespace in property
            right = JXG.GeonextParser.geonext2JS(right, this);
            right = right.replace(/this\.board\./g, 'this.');

            // Debug
            if (!JXG.exists(this.elementsByName[name])) {
                JXG.debug("debug conditions: |" + name + "| undefined");
            }
            plaintext += "el = this.objects[\"" + el.id + "\"];\n";

            switch (property) {
                case 'x':
                    plaintext += 'var y=el.coords.usrCoords[2];\n';  // y stays
                    plaintext += 'el.setPositionDirectly(JXG.COORDS_BY_USER,[' + (right) + ',y]);\n';
                    plaintext += 'el.prepareUpdate().update();\n';
                    break;
                case 'y':
                    plaintext += 'var x=el.coords.usrCoords[1];\n';  // x stays
                    plaintext += 'el.coords=new JXG.Coords(JXG.COORDS_BY_USER,[x,' + (right) + '],this);\n';
                    plaintext += 'el.setPositionDirectly(JXG.COORDS_BY_USER,[x,' + (right) + ']);\n';
                    plaintext += 'el.prepareUpdate().update();\n';
                    break;
                case 'visible':
                    plaintext += 'var c=' + (right) + ';\n';
                    plaintext += 'el.visProp.visible = c;\n';
                    plaintext += 'if (c) {el.showElement();} else {el.hideElement();}\n';
                    break;
                case 'position':
                    plaintext += 'el.position = ' + (right) + ';\n';
                    plaintext += 'el.prepareUpdate().update(true);\n';
                    break;
                case 'stroke':
                    plaintext += 'rgbo = JXG.rgba2rgbo(' + (right) + ');\n';
                    plaintext += 'el.visProp.strokecolor = rgbo[0];\n';
                    plaintext += 'el.visProp.strokeopacity = rgbo[1];\n';
                    break;
                case 'style':
                    plaintext += 'el.setStyle(' + (right) + ');\n';
                    break;
                case 'strokewidth':
                    plaintext += 'el.strokeWidth = ' + (right) + ';\n';
                    break;
                case 'fill':
                    plaintext += 'var rgbo = JXG.rgba2rgbo(' + (right) + ');\n';
                    plaintext += 'el.visProp.fillcolor = rgbo[0];\n';
                    plaintext += 'el.visProp.fillopacity = rgbo[1];\n';
                    break;
                case 'label':
                    break;
                default:
                    JXG.debug("property '" + property + "' in conditions not yet implemented:" + right);
                    break;
            }
            str = str.slice(j + 7); // cut off "</data>"
            i = str.indexOf('<data>');
            j = str.indexOf('<' + '/data>');
        }
        plaintext += 'this.prepareUpdate().updateElements();\n';
        plaintext += 'return true;\n';

        plaintext = plaintext.replace(/&lt;/g, "<");
        plaintext = plaintext.replace(/&gt;/g, ">");
        plaintext = plaintext.replace(/&amp;/g, "&");

        // eval required
        this.updateConditions = new Function(plaintext);
        this.updateConditions();
    },

    /**
     * Computes the commands in the conditions-section of the gxt file.
     * It is evaluated after an update, before the unsuspendRedraw.
     * The function is generated in
     * @see JXG.Board#addConditions
     * @private
     */
    updateConditions: function () {
        return false;
    },

    /**
     * Calculates adequate snap sizes.
     * @returns {JXG.Board} Reference to the board.
     */
    calculateSnapSizes: function () {
        var p1 = new JXG.Coords(JXG.COORDS_BY_USER, [0, 0], this),
            p2 = new JXG.Coords(JXG.COORDS_BY_USER, [this.options.grid.gridX, this.options.grid.gridY], this),
            x = p1.scrCoords[1]-p2.scrCoords[1],
            y = p1.scrCoords[2]-p2.scrCoords[2];

        this.options.grid.snapSizeX = this.options.grid.gridX;
        while (Math.abs(x) > 25) {
            this.options.grid.snapSizeX *= 2;
            x /= 2;
        }

        this.options.grid.snapSizeY = this.options.grid.gridY;
        while (Math.abs(y) > 25) {
            this.options.grid.snapSizeY *= 2;
            y /= 2;
        }

        return this;
    },

    /**
     * Apply update on all objects with the new zoom-factors. Clears all traces.
     * @returns {JXG.Board} Reference to the board.
     */
    applyZoom: function () {
        var el, ob, len = this.objectsList.length;

        for (ob = 0; ob < len; ob++) {
            el = this.objectsList[ob];
            if (!el.visProp.frozen &&
                    (el.elementClass === JXG.OBJECT_CLASS_POINT ||
                    el.elementClass === JXG.OBJECT_CLASS_CURVE ||
                    el.type === JXG.OBJECT_TYPE_AXIS ||
                    el.type === JXG.OBJECT_TYPE_TEXT)) {
                if (el.elementClass !== JXG.OBJECT_CLASS_CURVE && 
                        el.type !== JXG.OBJECT_TYPE_AXIS) {
                    el.coords.usr2screen();
                }
            }
        }
        this.calculateSnapSizes();
        this.clearTraces();
        this.fullUpdate();

        return this;
    },

    /**
     * Zooms into the board by the factors board.options.zoom.factorX and board.options.zoom.factorY and applies the zoom.
     * @returns {JXG.Board} Reference to the board
     */
    zoomIn: function (x, y) {
        var bb = this.getBoundingBox(),
            zX = this.options.zoom.factorX,
            zY = this.options.zoom.factorY,
            dX = (bb[2] - bb[0]) * (1.0 - 1.0 / zX),
            dY = (bb[1] - bb[3]) * (1.0 - 1.0 / zY),
            lr = 0.5, tr = 0.5;

        if (typeof x === 'number' && typeof y === 'number') {
            lr = (x - bb[0])/(bb[2] - bb[0]);
            tr = (bb[1] - y)/(bb[1] - bb[3]);
        }

        this.setBoundingBox([bb[0]+dX*lr, bb[1]-dY*tr, bb[2]-dX*(1-lr), bb[3]+dY*(1-tr)], false);
        this.zoomX *= zX;
        this.zoomY *= zY;
        this.applyZoom();

        return this;
    },

    /**
     * Zooms out of the board by the factors board.options.zoom.factorX and board.options.zoom.factorY and applies the zoom.
     * @returns {JXG.Board} Reference to the board
     */
    zoomOut: function (x, y) {
        var bb = this.getBoundingBox(),
            zX = this.options.zoom.factorX,
            zY = this.options.zoom.factorY,
            dX = (bb[2] - bb[0]) * (1.0 - zX),
            dY = (bb[1] - bb[3]) * (1.0 - zY),
            lr = 0.5, tr = 0.5;

        if (this.zoomX < JXG.Options.zoom.eps || this.zoomY < JXG.Options.zoom.eps) {
            return this;
        }

        if (typeof x === 'number' && typeof y === 'number') {
            lr = (x - bb[0])/(bb[2] - bb[0]);
            tr = (bb[1] - y)/(bb[1] - bb[3]);
        }

        this.setBoundingBox([bb[0]+dX*lr, bb[1]-dY*tr, bb[2]-dX*(1-lr), bb[3]+dY*(1-tr)], false);
        this.zoomX /= zX;
        this.zoomY /= zY;

        this.applyZoom();
        return this;
    },

    /**
     * Resets zoom factor to 100%.
     * @returns {JXG.Board} Reference to the board
     */
    zoom100: function () {
        var bb = this.getBoundingBox(),
            dX = (bb[2]-bb[0])*(1.0-this.zoomX)*0.5,
            dY = (bb[1]-bb[3])*(1.0-this.zoomY)*0.5;

        this.setBoundingBox([bb[0]+dX, bb[1]-dY, bb[2]-dX, bb[3]+dY], false);
        this.zoomX = 1.0;
        this.zoomY = 1.0;
        this.applyZoom();
        return this;
    },

    /**
     * Zooms the board so every visible point is shown. Keeps aspect ratio.
     * @returns {JXG.Board} Reference to the board
     */
    zoomAllPoints: function () {
        var minX = 0,
            maxX = 0,
            minY = 0,
            maxY = 0,
            el, border, borderX, borderY, len = this.objectsList.length, pEl;

        for (el = 0; el < len; el++) {
            pEl = this.objectsList[el];
            
            if (JXG.isPoint(pEl) && pEl.visProp.visible) {
                if (pEl.coords.usrCoords[1] < minX) {
                    minX = pEl.coords.usrCoords[1];
                } else if (pEl.coords.usrCoords[1] > maxX) {
                    maxX = pEl.coords.usrCoords[1];
                }
                if (pEl.coords.usrCoords[2] > maxY) {
                    maxY = pEl.coords.usrCoords[2];
                } else if (pEl.coords.usrCoords[2] < minY) {
                    minY = pEl.coords.usrCoords[2];
                }
            }
        }

        border = 50;
        borderX = border/(this.unitX);
        borderY = border/(this.unitY);

        this.zoomX = 1.0;
        this.zoomY = 1.0;

        this.setBoundingBox([minX-borderX, maxY+borderY, maxX+borderX, minY-borderY], true);

        this.applyZoom();

        return this;
    },

    /**
     * Reset the bounding box and the zoom level to 100% such that a given set of elements is within the board's viewport.
     * @param {Array} elements A set of elements given by id, reference, or name.
     * @returns {JXG.Board} Reference to the board.
     */
    zoomElements: function (elements) {
        var i, j, e, box,
            newBBox = [0, 0, 0, 0],
            dir = [1, -1, -1, 1];

        if (!JXG.isArray(elements) || elements.length === 0) {
            return this;
        }

        for (i = 0; i < elements.length; i++) {
            e = JXG.getRef(this, elements[i]);

            box = e.bounds();
            if (JXG.isArray(box)) {
                if (JXG.isArray(newBBox)) {
                    for (j = 0; j < 4; j++) {
                        if (dir[j]*box[j] < dir[j]*newBBox[j]) {
                            newBBox[j] = box[j];
                        }
                    }
                } else {
                    newBBox = box;
                }
            }
        }

        if (JXG.isArray(newBBox)) {
            for (j = 0; j < 4; j++) {
                newBBox[j] -= dir[j];
            }

            this.zoomX = 1.0;
            this.zoomY = 1.0;
            this.setBoundingBox(newBBox, true);
        }

        return this;
    },

    /**
     * Sets the zoom level to <tt>fX</tt> resp <tt>fY</tt>.
     * @param {Number} fX
     * @param {Number} fY
     * @returns {JXG.Board}
     */
    setZoom: function (fX, fY) {
        var oX = this.options.zoom.factorX, oY = this.options.zoom.factorY;

        this.options.zoom.factorX = fX/this.zoomX;
        this.options.zoom.factorY = fY/this.zoomY;

        this.zoomIn();

        this.options.zoom.factorX = oX;
        this.options.zoom.factorY = oY;

        return this;
    },

    /**
     * Removes object from board and renderer.
     * @param {JXG.GeometryElement} object The object to remove.
     * @returns {JXG.Board} Reference to the board
     */
    removeObject: function (object) {
        var el, i;

        if (JXG.isArray(object)) {
            for (i=0; i<object.length; i++) {
                this.removeObject(object[i]);
            }

            return this;
        }

        object = JXG.getReference(this, object);

        // If the object which is about to be removed unknown, do nothing.
        if (!JXG.exists(object)) {
            return this;
        }

        try {
            // remove all children.
            for (el in object.childElements) {
                if (object.childElements.hasOwnProperty(el)) {
                    object.childElements[el].board.removeObject(object.childElements[el]);
                }
            }

            for (el in this.objects) {
                if (this.objects.hasOwnProperty(el) && JXG.exists(this.objects[el].childElements)) {
                    delete(this.objects[el].childElements[object.id]);
                    delete(this.objects[el].descendants[object.id]);
                }
            }

            // remove the object itself from our control structures
            if (object._pos > -1) {
                this.objectsList.splice(object._pos, 1);
                for (el = object._pos; el < this.objectsList.length; el++) {
                    this.objectsList[el]._pos--;
                }
            } else {
                JXG.debug('object ' + object.id + ' not found in list.');
            }
            delete(this.objects[object.id]);
            delete(this.elementsByName[object.name]);

            if (object.visProp && object.visProp.trace) {
                object.clearTrace();
            }

            // the object deletion itself is handled by the object.
            if (JXG.exists(object.remove)) {
                object.remove();
            }
        } catch(e) {
            JXG.debug(object.id + ': Could not be removed: ' + e);
        }

        this.update();

        return this;
    },


    /**
     * Removes the ancestors of an object an the object itself from board and renderer.
     * @param {JXG.GeometryElement} object The object to remove.
     * @returns {JXG.Board} Reference to the board
     */
    removeAncestors: function (object) {
        var anc;

        for (anc in object.ancestors) {
            if (object.ancestors.hasOwnProperty(anc)) {
                this.removeAncestors(object.ancestors[anc]);
            }
        }
            
        this.removeObject(object);

        return this;
    },

    /**
     * Initialize some objects which are contained in every GEONExT construction by default,
     * but are not contained in the gxt files.
     * @returns {JXG.Board} Reference to the board
     */
    initGeonextBoard: function () {
        var p1, p2, p3, l1, l2;

        p1 = this.create('point', [0, 0], {
            id: this.id + 'g00e0',
            name: 'Ursprung',
            withLabel: false,
            visible: false,
            fixed: true
        });

        p2 = this.create('point', [1, 0], {
            id: this.id + 'gX0e0',
            name: 'Punkt_1_0',
            withLabel: false,
            visible: false,
            fixed: true
        });

        p3 = this.create('point', [0, 1], {
            id: this.id + 'gY0e0',
            name: 'Punkt_0_1',
            withLabel: false,
            visible: false,
            fixed: true
        });

        l1 = this.create('line', [p1, p2], {
            id: this.id + 'gXLe0',
            name: 'X-Achse',
            withLabel: false,
            visible: false
        });

        l2 = this.create('line', [p1, p3], {
            id: this.id + 'gYLe0',
            name: 'Y-Achse',
            withLabel: false,
            visible: false
        });

        return this;
    },

    /**
     * Initialize the info box object which is used to display
     * the coordinates of points near the mouse pointer,
     * @returns {JXG.Board} Reference to the board
     */
    initInfobox: function () {
        var  attr = JXG.copyAttributes({}, this.options, 'infobox');

        attr.id = this.id + '_infobox';

        this.infobox = this.create('text', [0, 0, '0,0'], attr);

        this.infobox.distanceX = -20;
        this.infobox.distanceY = 25;
        this.infobox.needsUpdateSize = false;  // That is not true, but it speeds drawing up.

        this.infobox.dump = false;

        this.renderer.hide(this.infobox);
        return this;
    },

    /**
     * Change the height and width of the board's container.
     * @param {Number} canvasWidth New width of the container.
     * @param {Number} canvasHeight New height of the container.
     * @returns {JXG.Board} Reference to the board
     */
    resizeContainer: function (canvasWidth, canvasHeight) {
        this.canvasWidth = parseFloat(canvasWidth, 10);
        this.canvasHeight = parseFloat(canvasHeight, 10);
        this.containerObj.style.width = (this.canvasWidth) + 'px';
        this.containerObj.style.height = (this.canvasHeight) + 'px';

        this.renderer.resize(this.canvasWidth, this.canvasHeight);

        return this;
    },

    /**
     * Lists the dependencies graph in a new HTML-window.
     * @returns {JXG.Board} Reference to the board
     */
    showDependencies: function () {
        var el, t, c, f, i;

        t = '<p>\n';
        for (el in this.objects) {
            if (this.objects.hasOwnProperty(el)) {
                i = 0;
                for (c in this.objects[el].childElements) {
                    if (this.objects[el].childElements.hasOwnProperty(c)) {
                        i++;
                    }
                }
                if (i >= 0) {
                    t += '<strong>' + this.objects[el].id + ':<'+'/strong> ';
                }
                for (c in this.objects[el].childElements) {
                    if (this.objects[el].childElements.hasOwnProperty(c)) {
                        t += this.objects[el].childElements[c].id+'('+this.objects[el].childElements[c].name+')'+', ';
                    }
                }
                t += '<p>\n';
            }
        }
        t += '<'+'/p>\n';
        f = window.open();
        f.document.open();
        f.document.write(t);
        f.document.close();
        return this;
    },

    /**
     * Lists the XML code of the construction in a new HTML-window.
     * @returns {JXG.Board} Reference to the board
     */
    showXML: function () {
        var f = window.open('');
        f.document.open();
        f.document.write('<pre>'+JXG.escapeHTML(this.xmlString)+'<'+'/pre>');
        f.document.close();
        return this;
    },

    /**
     * Sets for all objects the needsUpdate flag to "true".
     * @returns {JXG.Board} Reference to the board
     */
    prepareUpdate: function () {
        var el, pEl, len = this.objectsList.length;

        for (el = 0; el < len; el++) {
            pEl = this.objectsList[el];
            pEl.needsUpdate = pEl.needsRegularUpdate || this.needsFullUpdate;
        }
        return this;
    },

    /**
     * Runs through all elements and calls their update() method.
     * @param {JXG.GeometryElement} drag Element that caused the update.
     * @returns {JXG.Board} Reference to the board
     */
    updateElements: function (drag) {
        var el, pEl;

        drag = JXG.getRef(this, drag);

        for (el = 0; el < this.objectsList.length; el++) {
            pEl = this.objectsList[el];
            // For updates of an element we distinguish if the dragged element is updated or
            // other elements are updated.
            // The difference lies in the treatment of gliders.
            pEl.update(!JXG.exists(drag) || pEl.id !== drag.id);
        }

        return this;
    },

    /**
     * Runs through all elements and calls their update() method.
     * @param {JXG.GeometryElement} drag Element that caused the update.
     * @returns {JXG.Board} Reference to the board
     */
    updateRenderer: function (drag) {
        var el, pEl, len = this.objectsList.length;

        if (this.options.renderer === 'canvas') {
            this.updateRendererCanvas(drag);
        } else {
            for (el = 0; el < len; el++) {
                pEl = this.objectsList[el];
                pEl.updateRenderer();
            }
        }
        return this;
    },

    /**
     * Runs through all elements and calls their update() method.
     * This is a special version for the CanvasRenderer.
     * Here, we have to do our own layer handling.
     * @param {JXG.GeometryElement} drag Element that caused the update.
     * @returns {JXG.Board} Reference to the board
     */
    updateRendererCanvas: function (drag) {
        var el, pEl, i, olen = this.objectsList.length,
            layers = this.options.layer,
            len = this.options.layer.numlayers,
            last = Number.NEGATIVE_INFINITY, mini, la;

        for (i = 0; i < len; i++) {
            mini = Number.POSITIVE_INFINITY;
            
            for (la in layers) {
                if (layers.hasOwnProperty(la)) {
                    if (layers[la] > last && layers[la] < mini) {
                        mini = layers[la];
                    }
                }
            }
            
            last = mini;
            
            for (el = 0; el < olen; el++) {
                pEl = this.objectsList[el];
                
                if (pEl.visProp.layer === mini) {
                    pEl.prepareUpdate().updateRenderer();
                }
            }
        }
        return this;
    },

    /**
     * Please use {@link JXG.Board#on} instead.
     * @param {Function} hook A function to be called by the board after an update occured.
     * @param {String} [m='update'] When the hook is to be called. Possible values are <i>mouseup</i>, <i>mousedown</i> and <i>update</i>.
     * @param {Object} [context=board] Determines the execution context the hook is called. This parameter is optional, default is the
     * board object the hook is attached to.
     * @returns {Number} Id of the hook, required to remove the hook from the board.
     * @deprecated
     */
    addHook: function (hook, m, context) {
        m = JXG.def(m, 'update');

        context = JXG.def(context, this);

        this.hooks.push([m, hook]);
        this.on(m, hook, context);

        return this.hooks.length - 1;
    },

    /**
     * Alias of {@link JXG.Board#on}.
     */
    addEvent: JXG.shortcut(JXG.Board.prototype, 'on'),

    /**
     * Please use {@link JXG.Board#off} instead.
     * @param {Number|function} id The number you got when you added the hook or a reference to the event handler.
     * @returns {JXG.Board} Reference to the board
     * @deprecated
     */
    removeHook: function (id) {
        if (this.hooks[id]) {
            this.off(this.hooks[id][0], this.hooks[id][1]);
            this.hooks[id] = null;
        }

        return this;
    },

    /**
     * Alias of {@link JXG.Board#off}.
     */
    removeEvent: JXG.shortcut(JXG.Board.prototype, 'off'),

    /**
     * Runs through all hooked functions and calls them.
     * @returns {JXG.Board} Reference to the board
     * @deprecated
     */
    updateHooks: function (m) {
        var arg = Array.prototype.slice.call(arguments, 0);
        
        arg[0] = JXG.def(arg[0], 'update');
        this.triggerEventHandlers.apply(this, arguments);

        return this;
    },

    /**
     * Adds a dependent board to this board.
     * @param {JXG.Board} board A reference to board which will be updated after an update of this board occured.
     * @returns {JXG.Board} Reference to the board
     */
    addChild: function (board) {
        if (board!==null && JXG.exists(board.containerObj)) {
            this.dependentBoards.push(board);
            this.update();
        }
        return this;
    },

    /**
     * Deletes a board from the list of dependent boards.
     * @param {JXG.Board} board Reference to the board which will be removed.
     * @returns {JXG.Board} Reference to the board
     */
    removeChild: function (board) {
        var i;
        
        for (i = this.dependentBoards.length - 1; i >= 0; i--) {
            if (this.dependentBoards[i] === board) {
                this.dependentBoards.splice(i,1);
            }
        }
        return this;
    },

    /**
     * Runs through most elements and calls their update() method and update the conditions.
     * @param {Object} [drag] Element that caused the update.
     * @returns {JXG.Board} Reference to the board
     */
    update: function (drag) {
        var i, len, boardId, b;

        if (this.inUpdate || this.isSuspendedUpdate) {
            return this;
        }
        this.inUpdate = true;

        this.prepareUpdate(drag).updateElements(drag).updateConditions();
        this.renderer.suspendRedraw(this);
        this.updateRenderer(drag);
        this.renderer.unsuspendRedraw();
        this.triggerEventHandlers('update');

        // To resolve dependencies between boards
        //for (var board in JXG.JSXGraph.boards) {
        len = this.dependentBoards.length;
        for (i = 0; i < len; i++) {
            // boardId = this.dependentBoards[i].id;
            // b = JXG.JSXGraph.boards[boardId];
            b = this.dependentBoards[i];
            if ( JXG.exists(b) && b !== this) {
                b.updateQuality = this.updateQuality;
                b.prepareUpdate().updateElements().updateConditions();
                b.renderer.suspendRedraw();
                b.updateRenderer();
                b.renderer.unsuspendRedraw();
                b.triggerEventHandlers('update');
            }

        }

        this.inUpdate = false;
        return this;
    },

    /**
     * Runs through all elements and calls their update() method and update the conditions.
     * This is necessary after zooming and changing the bounding box.
     * @returns {JXG.Board} Reference to the board
     */
    fullUpdate: function () {
        this.needsFullUpdate = true;
        this.update();
        this.needsFullUpdate = false;
        return this;
    },

    /**
     * Adds a grid to the board according to the settings given in board.options.
     * @returns {JXG.Board} Reference to the board.
     */
    addGrid: function () {
        this.create('grid', []);

        return this;
    },

    /**
     * Removes all grids assigned to this board. Warning: This method also removes all objects depending on one or
     * more of the grids.
     * @returns {JXG.Board} Reference to the board object.
     */
    removeGrids: function () {
        var i;

        for (i = 0; i < this.grids.length; i++) {
            this.removeObject(this.grids[i]);
        }

        this.grids.length = 0;
        this.update(); // required for canvas renderer

        return this;
    },

    /**
     * Creates a new geometric element of type elementType.
     * @param {String} elementType Type of the element to be constructed given as a string e.g. 'point' or 'circle'.
     * @param {Array} parents Array of parent elements needed to construct the element e.g. coordinates for a point or two
     * points to construct a line. This highly depends on the elementType that is constructed. See the corresponding JXG.create*
     * methods for a list of possible parameters.
     * @param {Object} [attributes] An object containing the attributes to be set. This also depends on the elementType.
     * Common attributes are name, visible, strokeColor.
     * @returns {Object} Reference to the created element. This is usually a GeometryElement, but can be an array containing
     * two or more elements.
     */
    create: function (elementType, parents, attributes) {
        var el, i;

        elementType = elementType.toLowerCase();

        if (!JXG.exists(parents)) {
            parents = [];
        }

        if (!JXG.exists(attributes)) {
            attributes = {};
        }

        for (i = 0; i < parents.length; i++) {
            if (elementType !== 'text' || i !== 2) {
                parents[i] = JXG.getReference(this, parents[i]);
            }
        }

        if (JXG.JSXGraph.elements[elementType] !== null) {
            if (typeof JXG.JSXGraph.elements[elementType] === 'function') {
                el = JXG.JSXGraph.elements[elementType](this, parents, attributes);
            } else {
                el = JXG.JSXGraph.elements[elementType].creator(this, parents, attributes);
            }
        } else {
            throw new Error("JSXGraph: JXG.createElement: Unknown element type given: " + elementType);
        }

        if (!JXG.exists(el)) {
            JXG.debug("JSXGraph: JXG.createElement: failure creating " + elementType);
            return el;
        }

        if (el.prepareUpdate && el.update && el.updateRenderer) {
            el.prepareUpdate().update().updateRenderer();
        }
        return el;
    },

    /**
     * Deprecated name for {@link JXG.Board#create}.
     * @deprecated
     */
    createElement: JXG.shortcut(JXG.Board.prototype, 'create'),


    /**
     * Delete the elements drawn as part of a trace of an element.
     * @returns {JXG.Board} Reference to the board
     */
    clearTraces: function () {
        var el;

        for (el = 0; el < this.objectsList.length; el++) {
            this.objectsList[el].clearTrace();
        }

        this.numTraces = 0;
        return this;
    },

    /**
     * Stop updates of the board.
     * @returns {JXG.Board} Reference to the board
     */
    suspendUpdate: function () {
        this.isSuspendedUpdate = true;
        return this;
    },

    /**
     * Enable updates of the board.
     * @returns {JXG.Board} Reference to the board
     */
    unsuspendUpdate: function () {
        this.isSuspendedUpdate = false;
        this.update();
        return this;
    },

    /**
     * Set the bounding box of the board.
     * @param {Array} bbox New bounding box [x1,y1,x2,y2]
     * @param {Boolean} [keepaspectratio=false] If set to true, the aspect ratio will be 1:1, but
     * the resulting viewport may be larger.
     * @returns {JXG.Board} Reference to the board
     */
    setBoundingBox: function (bbox, keepaspectratio) {
        var h, w,
            dim = JXG.getDimensions(this.container);
        
        if (!JXG.isArray(bbox)) {
            return this;
        }

        this.plainBB = bbox;

        this.canvasWidth = parseInt(dim.width, 10);
        this.canvasHeight = parseInt(dim.height, 10);
        w = this.canvasWidth;
        h = this.canvasHeight;
        if (keepaspectratio) {
            this.unitX = w/(bbox[2]-bbox[0]);
            this.unitY = h/(bbox[1]-bbox[3]);
            if (Math.abs(this.unitX)<Math.abs(this.unitY)) {
                this.unitY = Math.abs(this.unitX)*this.unitY/Math.abs(this.unitY);
            } else {
                this.unitX = Math.abs(this.unitY)*this.unitX/Math.abs(this.unitX);
            }
        } else {
            this.unitX = w/(bbox[2]-bbox[0]);
            this.unitY = h/(bbox[1]-bbox[3]);
        }

        this.moveOrigin(-this.unitX*bbox[0], this.unitY*bbox[1]);
        return this;
    },

    /**
     * Get the bounding box of the board.
     * @returns {Array} bounding box [x1,y1,x2,y2] upper left corner, lower right corner
     */
    getBoundingBox: function () {
        var ul = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0,0], this),
            lr = new JXG.Coords(JXG.COORDS_BY_SCREEN, [this.canvasWidth, this.canvasHeight], this);
        return [ul.usrCoords[1], ul.usrCoords[2], lr.usrCoords[1], lr.usrCoords[2]];
    },

    /**
     * Adds an animation. Animations are controlled by the boards, so the boards need to be aware of the
     * animated elements. This function tells the board about new elements to animate.
     * @param {JXG.GeometryElement} element The element which is to be animated.
     * @returns {JXG.Board} Reference to the board
     */
    addAnimation: function (element) {
        var that = this;
        
        this.animationObjects[element.id] = element;

        if (!this.animationIntervalCode) {
            this.animationIntervalCode = setInterval(function () {
                JXG.JSXGraph.boards[that.id].animate();
            }, element.board.options.animationDelay);
        }

        return this;
    },

    /**
     * Cancels all running animations.
     * @returns {JXG.Board} Reference to the board
     */
    stopAllAnimation: function () {
        var el;

        for (el in this.animationObjects) {
            if (this.animationObjects.hasOwnProperty(el) && JXG.exists(this.animationObjects[el])) {
                this.animationObjects[el] = null;
                delete(this.animationObjects[el]);
            }
        }

        clearInterval(this.animationIntervalCode);
        delete(this.animationIntervalCode);

        return this;
    },

    /**
     * General purpose animation function. This currently only supports moving points from one place to another. This
     * is faster than managing the animation per point, especially if there is more than one animated point at the same time.
     * @returns {JXG.Board} Reference to the board
     */
    animate: function () {
        var count = 0,
            el, o, newCoords, r, p, c,
            obj=null, cbtmp;

        for (el in this.animationObjects) {
            if (this.animationObjects.hasOwnProperty(el) && JXG.exists(this.animationObjects[el])) {
                count++;
                o = this.animationObjects[el];
                
                if (o.animationPath) {
                    if (JXG.isFunction (o.animationPath)) {
                        newCoords = o.animationPath(new Date().getTime() - o.animationStart);
                    } else {
                        newCoords = o.animationPath.pop();
                    }

                    if ((!JXG.exists(newCoords)) || (!JXG.isArray(newCoords) && isNaN(newCoords))) {
                        delete(o.animationPath);
                    } else {
                        //o.setPositionByTransform(JXG.COORDS_BY_USER, [newCoords[0] - o.coords.usrCoords[1], newCoords[1] - o.coords.usrCoords[2]]);
                        o.setPositionDirectly(JXG.COORDS_BY_USER, newCoords);
                        //this.update(o);  // May slow down the animation, but is important
                        // for dependent glider objects (see tangram.html).
                        // Otherwise the intended projection may be incorrect.
                        o.prepareUpdate().update().updateRenderer();
                        obj = o;
                    }
                }
                if (o.animationData) {
                    c = 0;

                    for (r in o.animationData) {
                        if (o.animationData.hasOwnProperty(r)) {
                            p = o.animationData[r].pop();

                            if (!JXG.exists(p)) {
                                delete(o.animationData[p]);
                            } else {
                                c++;
                                o.setProperty(r + ':' + p);
                            }
                        }
                    }

                    if (c === 0) {
                        delete(o.animationData);
                    }
                }

                if (!JXG.exists(o.animationData) && !JXG.exists(o.animationPath)) {
                    this.animationObjects[el] = null;
                    delete(this.animationObjects[el]);

                    if (JXG.exists(o.animationCallback)) {
                        cbtmp = o.animationCallback;
                        o.animationCallback = null;
                        cbtmp();
                    }
                }
            }
        }

        if (count === 0) {
            clearInterval(this.animationIntervalCode);
            delete(this.animationIntervalCode);
        } else {
            this.update(obj);
        }

        return this;
    },

    /**
     * Migrate the dependency properties of the point src
     * to the point dest and  delete the point src.
     * For example, a circle around the point src
     * receives the new center dest. The old center src
     * will be deleted.
     * @param {JXG.Point} src Original point which will be deleted
     * @param {JXG.Point} dest New point with the dependencies of src.
     * @returns {JXG.Board} Reference to the board
     */
    migratePoint: function(src, dest) {
        var child, childId, prop, found, i;

        src = JXG.getRef(this, src);
        dest = JXG.getRef(this, dest);

        for (childId in src.childElements) {
            if (src.childElements.hasOwnProperty(childId)) {
                child = src.childElements[childId];
                found = false;
                
                for (prop in child) {
                    if (child.hasOwnProperty(prop)) {
                        if (child[prop] ===  src) {
                            child[prop] = dest;
                            found = true;
                        }
                    }
                }
                
                if (found) {
                    delete src.childElements[childId];
                }

                for (i = 0; i < child.parents.length; i++) {
                    if (child.parents[i] === src.id) {
                        child.parents[i] = dest.id;
                    }
                }

                dest.addChild(child);
            }
        }
        this.removeObject(src);
        this.update();
        return this;
    },

    /**
     * Initializes color blindness simulation.
     * @param {String} deficiency Describes the color blindness deficiency which is simulated. Accepted values are 'protanopia', 'deuteranopia', and 'tritanopia'.
     * @returns {JXG.Board} Reference to the board
     */
    emulateColorblindness: function (deficiency) {
        var e, o;

        if (!JXG.exists(deficiency)) {
            deficiency = 'none';
        }

        if (this.currentCBDef === deficiency) {
            return this;
        }

        for (e in this.objects) {
            if (this.objects.hasOwnProperty(e)) {
                o = this.objects[e];
                
                if (deficiency !== 'none') {
                    if (this.currentCBDef === 'none') {
                        // this could be accomplished by JXG.extend, too. But do not use
                        // JXG.deepCopy as this could result in an infinite loop because in
                        // visProp there could be geometry elements which contain the board which
                        // contains all objects which contain board etc.
                        o.visPropOriginal = {
                            strokecolor: o.visProp.strokecolor,
                            fillcolor: o.visProp.fillcolor,
                            highlightstrokecolor: o.visProp.highlightstrokecolor,
                            highlightfillcolor: o.visProp.highlightfillcolor
                        };
                    }
                    o.setProperty({
                        strokecolor: JXG.rgb2cb(o.visPropOriginal.strokecolor, deficiency),
                        fillcolor: JXG.rgb2cb(o.visPropOriginal.fillcolor, deficiency),
                        highlightstrokecolor: JXG.rgb2cb(o.visPropOriginal.highlightstrokecolor, deficiency),
                        highlightfillcolor: JXG.rgb2cb(o.visPropOriginal.highlightfillcolor, deficiency)
                    });
                } else if (JXG.exists(o.visPropOriginal)) {
                    JXG.extend(o.visProp, o.visPropOriginal);
                }
            }
        }
        this.currentCBDef = deficiency;
        this.update();

        return this;
    },
    
    /**
     * Update CSS transformations
     */
    updateCSSTransforms: function () {
        var obj = this.containerObj,
            o = obj,
            o2 = obj;

        this.cssTransMat = JXG.getCSSTransformMatrix(o);

        /*
         * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe,
         * if not to the body. In IE and if we are in an position:absolute environment 
         * offsetParent walks up the DOM hierarchy.
         * In order to walk up the DOM hierarchy also in Mozilla and Webkit
         * we need the parentNode steps.
         */
        o = o.offsetParent;
        while (o) {
            this.cssTransMat = JXG.Math.matMatMult(JXG.getCSSTransformMatrix(o), this.cssTransMat);
            
            o2 = o2.parentNode;
            while (o2 !== o) {
                this.cssTransMat = JXG.Math.matMatMult(JXG.getCSSTransformMatrix(o), this.cssTransMat);
                o2 = o2.parentNode;
            }

            o = o.offsetParent;
        }
        this.cssTransMat = JXG.Math.inverse(this.cssTransMat);

        return this;
    },
    
    
    /* **************************
     *     EVENT DEFINITION
     * for documentation purposes
     * ************************** */

    //region Event handler documentation
    
    /**
     * @event
     * @description Whenever the user starts to touch or click the board.
     * @name JXG.Board#down
     * @param {Event} e The browser's event object.
     */
    __evt__down: function (e) { },

    /**
     * @event
     * @description Whenever the user starts to click on the board.
     * @name JXG.Board#mousedown
     * @param {Event} e The browser's event object.
     */
    __evt__mousedown: function (e) { },

    /**
     * @event
     * @description Whenever the user starts to touch the board.
     * @name JXG.Board#touchstart
     * @param {Event} e The browser's event object.
     */
    __evt__touchstart: function (e) { },

    /**
     * @event
     * @description Whenever the user stops to touch or click the board.
     * @name JXG.Board#up
     * @param {Event} e The browser's event object.
     */
    __evt__up: function (e) { },

    /**
     * @event
     * @description Whenever the user releases the mousebutton over the board.
     * @name JXG.Board#mouseup
     * @param {Event} e The browser's event object.
     */
    __evt__mouseup: function (e) { },

    /**
     * @event
     * @description Whenever the user stops touching the board.
     * @name JXG.Board#touchend
     * @param {Event} e The browser's event object.
     */
    __evt__touchend: function (e) { },
    
    /**
     * @event
     * @description This event is fired whenever the user is moving the finger or mouse pointer over the board.
     * @name JXG.Board#move
     * @param {Event} e The browser's event object.
     * @param {Number} mode The mode the board currently is in
     * @see {JXG.Board#mode}
     */
    __evt__move: function (e, mode) { },

    /**
     * @event
     * @description This event is fired whenever the user is moving the mouse over the board.
     * @name JXG.Board#mousemove
     * @param {Event} e The browser's event object.
     * @param {Number} mode The mode the board currently is in
     * @see {JXG.Board#mode}
     */
    __evt__mousemove: function (e, mode) { },
    
    /**
     * @event
     * @description This event is fired whenever the user is moving the finger over the board.
     * @name JXG.Board#touchmove
     * @param {Event} e The browser's event object.
     * @param {Number} mode The mode the board currently is in
     * @see {JXG.Board#mode}
     */
    __evt__touchmove: function (e, mode) { },

    /**
     * @event
     * @description Whenever an element is highlighted this event is fired.
     * @name JXG.Board#hit
     * @param {Event} e The browser's event object.
     * @param {JXG.GeoemtryElement} el The hit element.
     * @param {%} target ?
     */
    __evt__hit: function (e, el, target) { },

    /**
     * @event
     * @description Whenever an element is highlighted this event is fired.
     * @name JXG.Board#mousehit
     * @param {Event} e The browser's event object.
     * @param {JXG.GeoemtryElement} el The hit element.
     * @param {%} target ?
     */
    __evt__mousehit: function (e, el, target) { },
    
    /**
     * @event
     * @description This board is updated.
     * @name JXG.Board#update
     */
    __evt__update: function () { },

    /**
     * @ignore
     */
    __evt__: function () {},
        
    //endregion

    /**
     * Return all elements that somehow depend on the element <tt>root</tt> and satisfy one of the <tt>filter</tt> rules.
     * <tt>filters</tt> are objects which's properties are compared to every element found in the dependency tree.
     * @param {JXG.GeometryElement} root Dependency tree root element
     * @param {Object} filt An arbitrary amount of objects which define filters for the elements to return. Only elements
     * that fulfill at least one filter are returned. The comparison is a direct comparison, i.e. nested objects won't be
     * compared.
     * @example
     * // This will return only points
     * var partPoints = board.getPartialConstruction(p, {elementClass: JXG.OBJECT_CLASS_POINT});
     *
     * // This will return only points and lines
     * var partPointsLines = board.getPartialConstruction(p, {elementClass: JXG.OBJECT_CLASS_POINT}, {elementClass: JXG.OBJECT_CLASS_LINE});
     */
    getPartialConstruction: function (root, filt) {
        var filters, i;

        for (i = 1; i < arguments.length; i++) {
            filters.push(arguments[i]);
        }
        
        // I guess this needs some implementation
    },

    /**
     * Function to animate a curve rolling on another curve.
     * @param {Curve} c1 JSXGraph curve building the floor where c2 rolls
     * @param {Curve} c2 JSXGraph curve which rolls on c1.
     * @param {number} start_c1 The parameter t such that c1(t) touches c2. This is the start position of the
     *                          rolling process
     * @param {Number} stepsize Increase in t in each step for the curve c1
     * @param {Number} direction
     * @param {Number} time Delay time for setInterval()
     * @param {Array} pointlist Array of points which are rolled in each step. This list should contain
     *      all points which define c2 and gliders on c2.
     *
     * @example
     *
     * // Line which will be the floor to roll upon.
     * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6});
     * // Center of the rolling circle
     * var C = brd.create('point',[0,2],{name:'C'});
     * // Starting point of the rolling circle
     * var P = brd.create('point',[0,1],{name:'P', trace:true});
     * // Circle defined as a curve. The circle "starts" at P, i.e. circle(0) = P
     * var circle = brd.create('curve',[
     *           function (t){var d = P.Dist(C),
     *                           beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);
     *                       t += beta;
     *                       return C.X()+d*Math.cos(t);
     *           },
     *           function (t){var d = P.Dist(C),
     *                           beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);
     *                       t += beta;
     *                       return C.Y()+d*Math.sin(t);
     *           },
     *           0,2*Math.PI],
     *           {strokeWidth:6, strokeColor:'green'});
     *
     * // Point on circle
     * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false});
     * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]);
     * roll.start() // Start the rolling, to be stopped by roll.stop()
     *
     * </pre><div id="e5e1b53c-a036-4a46-9e35-190d196beca5" style="width: 300px; height: 300px;"></div>
     * <script type="text/javascript">
     * var brd = JXG.JSXGraph.initBoard('e5e1b53c-a036-4a46-9e35-190d196beca5', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false});
     * // Line which will be the floor to roll upon.
     * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6});
     * // Center of the rolling circle
     * var C = brd.create('point',[0,2],{name:'C'});
     * // Starting point of the rolling circle
     * var P = brd.create('point',[0,1],{name:'P', trace:true});
     * // Circle defined as a curve. The circle "starts" at P, i.e. circle(0) = P
     * var circle = brd.create('curve',[
     *           function (t){var d = P.Dist(C),
     *                           beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);
     *                       t += beta;
     *                       return C.X()+d*Math.cos(t);
     *           },
     *           function (t){var d = P.Dist(C),
     *                           beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);
     *                       t += beta;
     *                       return C.Y()+d*Math.sin(t);
     *           },
     *           0,2*Math.PI],
     *           {strokeWidth:6, strokeColor:'green'});
     *
     * // Point on circle
     * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false});
     * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]);
     * roll.start() // Start the rolling, to be stopped by roll.stop()
     * </script><pre>
     *
     */
    createRoulette: function (c1, c2, start_c1, stepsize, direction, time, pointlist) {
        var brd = this,
            Roulette = function () {
            var alpha = 0, Tx = 0, Ty = 0,
                t1 = start_c1,
                t2 = JXG.Math.Numerics.root(
                    function (t) {
                        var c1x = c1.X(t1),
                            c1y = c1.Y(t1),
                            c2x = c2.X(t),
                            c2y = c2.Y(t);
                        return (c1x-c2x)*(c1x-c2x) + (c1y-c2y)*(c1y-c2y);
                    },
                    [0,Math.PI*2]),
                t1_new = 0.0, t2_new = 0.0,
                c1dist,
                rotation = brd.create('transform',[function (){ return alpha;}], {type:'rotate'}),
                rotationLocal = brd.create('transform',[function (){ return alpha;},
                    function (){ return c1.X(t1);},
                    function (){ return c1.Y(t1);}],
                {type:'rotate'}),
                translate = brd.create('transform',[function (){ return Tx;}, function (){ return Ty;}], {type:'translate'}),

                //
                // arc length via Simpson's rule.
                arclen = function (c,a,b) {
                    var cpxa = JXG.Math.Numerics.D(c.X)(a), cpya = JXG.Math.Numerics.D(c.Y)(a),
                        cpxb = JXG.Math.Numerics.D(c.X)(b), cpyb = JXG.Math.Numerics.D(c.Y)(b),
                        cpxab = JXG.Math.Numerics.D(c.X)((a+b)*0.5), cpyab = JXG.Math.Numerics.D(c.Y)((a+b)*0.5),
                        fa = Math.sqrt(cpxa*cpxa+cpya*cpya),
                        fb = Math.sqrt(cpxb*cpxb+cpyb*cpyb),
                        fab = Math.sqrt(cpxab*cpxab+cpyab*cpyab);
                    return (fa+4*fab+fb)*(b-a)/6.0;
                },
                exactDist = function (t) {
                    return c1dist - arclen(c2,t2,t);
                },
                beta = Math.PI/18.0,
                beta9 = beta*9,
                interval = null;

            this.rolling = function (){
                var h, g, hp, gp, z;
                
                t1_new = t1+direction*stepsize;
                c1dist = arclen(c1,t1,t1_new);             // arc length between c1(t1) and c1(t1_new)
                t2_new = JXG.Math.Numerics.root(exactDist, t2);
                // find t2_new such that arc length between c2(t2) and c1(t2_new)
                // equals c1dist.

                h = new JXG.Complex(c1.X(t1_new),c1.Y(t1_new));    // c1(t) as complex number
                g = new JXG.Complex(c2.X(t2_new),c2.Y(t2_new));    // c2(t) as complex number
                hp = new JXG.Complex(JXG.Math.Numerics.D(c1.X)(t1_new),JXG.Math.Numerics.D(c1.Y)(t1_new));
                gp = new JXG.Complex(JXG.Math.Numerics.D(c2.X)(t2_new),JXG.Math.Numerics.D(c2.Y)(t2_new));
                z = JXG.C.div(hp,gp);                  // z is angle between the tangents of
                // c1 at t1_new, and c2 at t2_new
                alpha = Math.atan2(z.imaginary, z.real);
                z.div(JXG.C.abs(z));                       // Normalizing the quotient
                z.mult(g);
                Tx = h.real-z.real;
                Ty = h.imaginary-z.imaginary;              // T = h(t1_new)-g(t2_new)*h'(t1_new)/g'(t2_new);

                if (alpha <-beta && alpha>-beta9) {        // -(10-90) degrees: make corners roll smoothly
                    alpha = -beta;
                    rotationLocal.applyOnce(pointlist);
                } else if (alpha>beta && alpha<beta9) {
                    alpha = beta;
                    rotationLocal.applyOnce(pointlist);
                } else {
                    rotation.applyOnce(pointlist);
                    translate.applyOnce(pointlist);
                    t1 = t1_new;
                    t2 = t2_new;
                }
                brd.update();
            };

            this.start = function () {
                if (time>0) {
                    interval = setInterval(this.rolling, time);
                }
                return this;
            };

            this.stop = function () {
                clearInterval(interval);
                return this;
            };
            return this;
        };
        return new Roulette();
    }
});


/*
    Copyright 2008-2012
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * Options Namespace
 * @description These are the default options of the board and of all geometry elements.
 */
JXG.Options = {
    /* Options that are used directly within the board class */
    showCopyright : true,
    showNavigation : true,
    takeSizeFromFile : false, // If true, the construction - when read from a file or string - the size of the div can be changed.
    renderer: 'svg',
    takeFirst : false, // if true the first element with hasPoint==true is taken.
    animationDelay: 35,

    /* zoom options */
    zoom : {
        factorX : 1.25,
        factorY : 1.25,
        wheel: false,
        needShift: false,
        eps: 0.1
    },
    
    pan: {
        needShift: true,
        needTwoFingers: true,
        enabled: true
    },

    jc : {
        enabled: true,
        compile: true
    },

    /* navbar options */
    navbar: {
        strokeColor: '#aaaaaa',
        fillColor: '#f5f5f5',
        padding: '2px',
        position: 'absolute',
        fontSize: '10px',
        cursor: 'pointer',
        zIndex: '100',
        right: '5px',
        bottom: '5px'
    },

    /**
     * Generic options 
     */
    
    /* geometry element options */
    elements : {
        // the following tag is a meta tag: http://code.google.com/p/jsdoc-toolkit/wiki/MetaTags

        /**#@+
         * @visprop
         */

        /**
         * The stroke color of the given geometry element.
         * @type String
         * @name JXG.GeometryElement#strokeColor
         * @see JXG.GeometryElement#highlightStrokeColor
         * @see JXG.GeometryElement#strokeWidth
         * @see JXG.GeometryElement#strokeOpacity
         * @see JXG.GeometryElement#highlightStrokeOpacity
         * @default {@link JXG.Options.elements.color#strokeColor}
         */
        strokeColor: '#0000ff',

        /**
         * The stroke color of the given geometry element when the user moves the mouse over it.
         * @type String
         * @name JXG.GeometryElement#highlightStrokeColor
         * @see JXG.GeometryElement#strokeColor
         * @see JXG.GeometryElement#strokeWidth
         * @see JXG.GeometryElement#strokeOpacity
         * @see JXG.GeometryElement#highlightStrokeOpacity
         * @default {@link JXG.Options.elements.color#highlightStrokeColor}
         */
        highlightStrokeColor: '#C3D9FF',

        /**
         * The fill color of this geometry element.
         * @type String
         * @name JXG.GeometryElement#fillColor
         * @see JXG.GeometryElement#highlightFillColor
         * @see JXG.GeometryElement#fillOpacity
         * @see JXG.GeometryElement#highlightFillOpacity
         * @default {@link JXG.Options.elements.color#fillColor}
         */
        fillColor: 'red',

        /**
         * The fill color of the given geometry element when the mouse is pointed over it.
         * @type String
         * @name JXG.GeometryElement#highlightFillColor
         * @see JXG.GeometryElement#fillColor
         * @see JXG.GeometryElement#fillOpacity
         * @see JXG.GeometryElement#highlightFillOpacity
         * @default {@link JXG.Options.elements.color#highlightFillColor}
         */
        highlightFillColor: 'none',

        /**
         * Opacity for element's stroke color.
         * @type number
         * @name JXG.GeometryElement#strokeOpacity
         * @see JXG.GeometryElement#strokeColor
         * @see JXG.GeometryElement#highlightStrokeColor
         * @see JXG.GeometryElement#strokeWidth
         * @see JXG.GeometryElement#highlightStrokeOpacity
         * @default {@link JXG.Options.elements#strokeOpacity}
         */
        strokeOpacity: 1,

        /**
         * Opacity for stroke color when the object is highlighted.
         * @type number
         * @name JXG.GeometryElement#highlightStrokeOpacity
         * @see JXG.GeometryElement#strokeColor
         * @see JXG.GeometryElement#highlightStrokeColor
         * @see JXG.GeometryElement#strokeWidth
         * @see JXG.GeometryElement#strokeOpacity
         * @default {@link JXG.Options.elements#highlightStrokeOpacity}
         */
        highlightStrokeOpacity: 1,

        /**
         * Opacity for fill color.
         * @type number
         * @name JXG.GeometryElement#fillOpacity
         * @see JXG.GeometryElement#fillColor
         * @see JXG.GeometryElement#highlightFillColor
         * @see JXG.GeometryElement#highlightFillOpacity
         * @default {@link JXG.Options.elements.color#fillOpacity}
         */
        fillOpacity: 1,

        /**
         * Opacity for fill color when the object is highlighted.
         * @type number
         * @name JXG.GeometryElement#highlightFillOpacity
         * @see JXG.GeometryElement#fillColor
         * @see JXG.GeometryElement#highlightFillColor
         * @see JXG.GeometryElement#fillOpacity
         * @default {@link JXG.Options.elements.color#highlightFillOpacity}
         */
        highlightFillOpacity: 1,

        /**
         * Width of the element's stroke.
         * @type number
         * @name JXG.GeometryElement#strokeWidth
         * @see JXG.GeometryElement#strokeColor
         * @see JXG.GeometryElement#highlightStrokeColor
         * @see JXG.GeometryElement#strokeOpacity
         * @see JXG.GeometryElement#highlightStrokeOpacity
         * @default {@link JXG.Options.elements#strokeWidth}
         */
        strokeWidth: 2,

        /**
         * Width of the element's stroke when the mouse is pointed over it.
         * @type number
         * @name JXG.GeometryElement#highlightStrokeWidth
         * @see JXG.GeometryElement#strokeColor
         * @see JXG.GeometryElement#highlightStrokeColor
         * @see JXG.GeometryElement#strokeOpacity
         * @see JXG.GeometryElement#highlightStrokeOpacity
         * @see JXG.GeometryElement#highlightFillColor
         * @default {@link JXG.Options.elements#strokeWidth}
         */
        highlightStrokeWidth: 2,


        /**
         * If true the element is fixed and can not be dragged around. The element
         * will be repositioned on zoom and moveOrigin events.
         * @type Boolean
         * @default false
         * @name JXG.GeometryElement#fixed
         */
        fixed: false,

        /**
         * If true the element is fixed and can not be dragged around. The element
         * will even stay at its position on zoom and moveOrigin events.
         * Only free elements like points, texts, curves can be frozen.
         * @type Boolean
         * @default false
         * @name JXG.GeometryElement#frozen
         */
        frozen: false,

        /**
         * If true a label will display the element's name.
         * @type Boolean
         * @default false
         * @name JXG.GeometryElement#withLabel
         */
        withLabel: false,

        /**
         * If false the element won't be visible on the board, otherwise it is shown.
         * @type boolean
         * @name JXG.GeometryElement#visible
         * @see JXG.GeometryElement#hideElement
         * @see JXG.GeometryElement#showElement
         * @default true
         */
        visible: true,

        /**
         * A private element will be inaccessible in certain environments, e.g. a graphical user interface.
         * @default false
         */
        priv: false,

        /**
         * Display layer which will contain the element.
         * @see JXG.Options#layer
         * @default See {@link JXG.Options#layer}
         */
        layer: 0,


        /**
         * Determines the elements border-style.
         * Possible values are:
         * <ul><li>0 for a solid line</li>
         * <li>1 for a dotted line</li>
         * <li>2 for a line with small dashes</li>


         * <li>3 for a line with medium dashes</li>
         * <li>4 for a line with big dashes</li>
         * <li>5 for a line with alternating medium and big dashes and large gaps</li>
         * <li>6 for a line with alternating medium and big dashes and small gaps</li></ul>
         * @type Number
         * @name JXG.GeometryElement#dash
         * @default 0
         */
        dash: 0,

        /**
         * If true the element will get a shadow.
         * @type boolean
         * @name JXG.GeometryElement#shadow
         * @default false
         */
        shadow: false,

        /**
         * If true the element will be traced, i.e. on every movement the element will be copied
         * to the background. Use {@link JXG.GeometryElement#clearTrace} to delete the trace elements.
         * @see JXG.GeometryElement#clearTrace
         * @see JXG.GeometryElement#traces
         * @see JXG.GeometryElement#numTraces
         * @type Boolean
         * @default false
         * @name JXG.GeometryElement#trace
         */
        trace: false,

        /**
         * Extra visual properties for traces of an element
         * @type Object
         * @see JXG.GeometryElement#trace
         * @name JXG.GeometryElement#traceAttributes
         */
        traceAttributes: {},
        
        /**
         * 
         * @type Boolean
         * @default true
         * @name JXG.GeometryElement#highlight
         */
        highlight: true,
        
        /**
         * If this is set to true, the element is updated in every update
         * call of the board. If set to false, the element is updated only after
         * zoom events or more generally, when the bounding box has been changed.
         * Examples for the latter behaviour should be axes.
         * @type Boolean
         * @default true
         * @see JXG.GeometryElement#needsRegularUpdate
         * @name JXG.GeometryElement#needsRegularUpdate
         */
        needsRegularUpdate: true,

        /**
         * Snaps the element or its parents to the grid. Currently only relevant for points, circles,
         * and lines. Points are snapped to grid directly, on circles and lines it's only the parent
         * points that are snapped
         * @type Boolean
         * @default false
         * @name JXG.GeometryElement#snapToGrid
         */
        snapToGrid: false,

        /**
         * Determines whether two-finger manipulation of this object may change its size.
         * If set to false, the object is only rotated and translated.
         * @type Boolean
         * @default true
         * @name JXG.GeometryElement#scalable
         */
        scalable: true,

        /*draft options */
        draft : {
            /**
             * If true the element will be drawn in grey scale colors to visualize that it's only a draft.
             * @type boolean
             * @name JXG.GeometryElement#draft
             * @default {@link JXG.Options.elements.draft#draft}
             */
            draft : false,
            strokeColor : '#565656',
            fillColor : '#565656',
            strokeOpacity : 0.8,
            fillOpacity : 0.8,
            strokeWidth : 1
        }
        // close the meta tag
        /**#@-*/
    },

    ticks : {
        /**#@+
         * @visprop
         */

        /**
         * Draw labels yes/no
         * @type Boolean
         * @name JXG.Ticks#drawLabels
         * @default false
         */
        drawLabels: false,
        label:{},
       
        /**
         * Draw the zero tick, that lies at line.point1?
         * @type Boolean
         * @name JXG.Ticks#drawZero
         * @default false
         */
        drawZero: false,

        /**
         * If the distance between two ticks is too big we could insert new ticks. If insertTicks
         * is <tt>true</tt>, we'll do so, otherwise we leave the distance as is.
         * This option is ignored if equidistant is false.
         * @type Boolean
         * @name JXG.Ticks#insertTicks
         * @see JXG.Ticks#equidistant
         * @see JXG.Ticks#maxTicksDistance
         * @default false
         */
        insertTicks: false,
        minTicksDistance: 50,

        /**
         * Total height of a minor tick. If negative the full height of the board is taken.
         * @type Number
         * @name JXG.Ticks#minorHeight
         */
        minorHeight: 4,

        /**
         * Total height of a major tick. If negative the full height of the board is taken.
         * @type Number
         * @name JXG.Ticks#majorHeight
         */
        majorHeight: 10,

        /**
         * The number of minor ticks between two major ticks.
         * @type Number
         * @name JXG.Ticks#minorTicks
         */
        minorTicks: 4,

        /**
         * Scale the ticks but not the tick labels.
         * @type Number
         * @default 1
         * @name JXG.Ticks#scale
         * @see JXG.Ticks#scaleSymbol
         */
        scale: 1,

        /**
         * A string that is appended to every tick, used to represent the scale
         * factor given in {@link JXG.Ticks#scaleSymbol}.
         * @type String
         * @default ''
         * @name JXG.Ticks#scaleSymbol
         * @see JXG.Ticks#scale
         */
        scaleSymbol: '',

        /**
         * User defined labels for special ticks. Instead of the i-th tick's position, the i-th string stored in this array
         * is shown. If the number of strings in this array is less than the number of special ticks, the tick's position is
         * shown as a fallback.
         * @type Array
         * @name JXG.Ticks#labels
         * @default []
         */
        labels: [],

        /**
         * The default distance between two ticks. Please be aware that this value does not have
         * to be used if {@link JXG.Ticks#insertTicks} is set to true.
         * @type Boolean
         * @name JXG.Ticks#ticksDistance
         * @see JXG.Ticks#equidistant
         * @see JXG.Ticks#insertTicks
         * @default 1
         */
        ticksDistance: 1,
        strokeOpacity: 1,
        strokeWidth: 1,
        strokeColor: 'black',
        highlightStrokeColor: '#888888'
        // close the meta tag
        /**#@-*/
    },

    /* precision options */
    precision : {
        touch    : 30,
        touchMax : 100,
        mouse    : 4,
        epsilon  : 0.0001,
        hasPoint : 4
    },

    /* Default ordering of the layers */
    layer : {
        numlayers: 20, // only important in SVG
        text  : 9,
        point : 9,   
        glider : 9,   
        arc   : 8,
        line  : 7,
        circle: 6, 
        curve : 5,
		turtle : 5,
        polygon: 3,
        sector: 3,
        angle : 3, 
        integral : 3,
        axis : 2,
        grid  : 1,
        image : 0,
        trace: 0
    },

    /**
     * element type specific options 
     */ 
    /* special angle options */
    angle : {
        withLabel: true,

        /**
         * Radius of the sector, displaying the angle.
         * @type Number
         * @default 0.5
         * @name Angle#radius
         * @visprop
         */
        radius : 0.5,
        
        /**
         * Display type of the angle field. Possible values are 
         * 'sector' or 'sectordot' or 'square' or 'none'.
         * @type String
         * @default sector
         * @name Angle#type
         * @visprop
         */
        type : 'sector',  
                
        /**
         * Display type of the angle field in case of a right angle. Possible values are 
         * 'sector' or 'sectordot' or 'square' or 'none'.
         * @type String
         * @default square
         * @name Angle#orthoType
         * @see Angle#orthoSensitivity
         * @visprop
         */
        orthoType: 'square',         

        /**
         * Sensitivity (in degrees) to declare an angle as right angle.
         * If the angle measure is inside this distance from a rigth angle, the orthoType
         * of the angle is used for display.
         * @type Number
         * @default 1.0
         * @name Angle#orthoSensitivity
         * @see Angle#orthoType
         * @visprop
         */
        orthoSensitivity: 1.0,     
        fillColor : '#FF7F00',
        highlightFillColor : '#FF7F00',
        strokeColor : '#FF7F00',
        fillOpacity : 0.3,
        highlightFillOpacity : 0.3,
        radiuspoint: {
            withLabel: false,
            visible: false,
            name: ''
        },
        pointsquare: {
            withLabel: false,
            visible: false,
            name: ''
        },
        dot: {
            visible: false,
            strokeColor: 'none',
            fillColor: 'black',
            size: 2,
            face: 'o',
            withLabel: false,
            name: ''
        },
        label: {
            position: 'top',
            offset: [0,0],
            strokeColor: '#0000FF'
        }
    },

    /* special arc options */
    arc : {
        label: {},
        firstArrow : false,
        lastArrow : false,
        fillColor : 'none',
        highlightFillColor : 'none',
        strokeColor : '#0000ff',
        highlightStrokeColor : '#C3D9FF',
        useDirection: false
    },
    
    inequality: {
        fillColor: 'red',
        fillOpacity: 0.2,
        strokeColor: 'none',

        /**
         * By default an inequality is less (or equal) than. Set inverse to <tt>true</tt> will consider the inequality
         * greater (or equal) than.
         * @type Boolean
         * @default false
         * @name Inequality#inverse
         * @visprop
         */
        inverse: false
    },

    /* special axis options */
    axis: {
        needsRegularUpdate : false,         // Axes only updated after zooming and moving of the origin.
        strokeWidth: 1,
        strokeColor : '#666666',
        highlightStrokeWidth: 1,
        highlightStrokeColor : '#888888',
        withTicks: true,
        straightFirst : true,
        straightLast : true,
        lastArrow: true,
        withLabel: false, 
        scalable: false,
        /* line ticks options */
        ticks : {
            label: { 
                offset:[4,-12+3]     // This seems to be a good offset for 12 point fonts
            },
            needsRegularUpdate : false,            
            strokeWidth: 1,
            strokeColor : '#666666',
            highlightStrokeColor : '#888888',
            drawLabels : true,
            drawZero : false,
            insertTicks : true,
            minTicksDistance : 10,
            minorHeight : 4,          // if <0: full width and height
            majorHeight : -1,         // if <0: full width and height
            minorTicks : 4,
            ticksDistance: 1,         // TODO doc
            strokeOpacity : 0.25
        },
        point1 : {                  // Default values for point1 if created by line
            needsRegularUpdate : false
        },
        point2 : {                  // Default values for point2 if created by line
            needsRegularUpdate : false
        },
        label: {
            position: 'lft',
            offset: [10,-20]
        }
    },
    
    /* special options for bisector of 3 points */
    bisector : {
        strokeColor: '#000000', // Bisector line
        point : {               // Bisector point
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        }
    },

    /* special options for the 2 bisectors of 2 lines */
    bisectorlines : {
        line1 : {               // 
            strokeColor: 'black'
        },
        line2 : {               // 
            strokeColor: 'black'
        }
    },

    /* special chart options */
    chart: {
        chartStyle: 'line',
        colors: ['#B02B2C','#3F4C6B','#C79810','#D15600','#FFFF88','#C3D9FF','#4096EE','#008C00'],
        highlightcolors: null,
        fillcolor: null,
        highlightonsector: false,
        highlightbysize: false
    },

    /*special circle options */
    circle : {
        hasInnerPoints: false,
        fillColor : 'none',
        highlightFillColor : 'none',
        strokeColor : '#0000ff',
        highlightStrokeColor : '#C3D9FF',
        center: {
            visible: false,
            withLabel: false,
            fixed: false,
            name: ''
        },
        label: {
            position: 'urt'
        }
    },

    /* special options for circumcircle of 3 points */
    circumcircle : {
        fillColor : 'none',
        highlightFillColor : 'none',
        strokeColor : '#0000ff',
        highlightStrokeColor : '#C3D9FF',
        center : {               // center point
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        }
    },

    circumcirclearc : {
        fillColor : 'none',
        highlightFillColor : 'none',
        strokeColor : '#0000ff',
        highlightStrokeColor : '#C3D9FF',
        center: {
            visible: false,
            withLabel: false,
            fixed: false,
            name: ''
        }
    },

    /* special options for circumcircle sector of 3 points */
    circumcirclesector: {
        useDirection: true,
        fillColor: '#00FF00',
        highlightFillColor: '#00FF00',
        fillOpacity: 0.3,
        highlightFillOpacity: 0.3,
        strokeColor : '#0000ff',
        highlightStrokeColor : '#C3D9FF',
        point: {
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        }
    },
    
    /* special conic options */
    conic : {
        fillColor : 'none',
        highlightFillColor : 'none',
        strokeColor : '#0000ff',
        highlightStrokeColor : '#C3D9FF',
        foci: {
            // points
            fixed: false,
            visible: false,
            withLabel: false,
            name: ''
        }
    },

    /* special curve options */
    curve : {
        strokeWidth : 1,
        strokeColor : '#0000ff',
        fillColor: 'none',
        fixed: true,
        
        /**#@+
         * @visprop
         */

       /**
        * The data points of the curve are not connected with straight lines but with bezier curves.
        * @name JXG.Curve#handDrawing
        * @type Boolean
        * @default false
        */
        handDrawing: false,

        /**
         * The curveType is set in @see generateTerm and used in {@link JXG.Curve#updateCurve}.
         * Possible values are <ul>
         * <li>'none'</li>
         * <li>'plot': Data plot</li>
         * <li>'parameter': we can not distinguish function graphs and parameter curves</li>
         * <li>'functiongraph': function graph</li>
         * <li>'polar'</li>
         * <li>'implicit' (not yet)</li></ul>
         * Only parameter and plot are set directly. Polar is set with setProperties only.
         * @name JXG.Curve#curveType
         */
        curveType: null,
        RDPsmoothing : false,     // Apply the Ramer-Douglas-Peuker algorithm
        numberPointsHigh : 1600,  // Number of points on curves after mouseUp
        numberPointsLow : 400,    // Number of points on curves after mousemove
        doAdvancedPlot : true,    // Use the algorithm by Gillam and Hohenwarter
                                 // It is much slower, but the result is better
        
        label: {
            position: 'lft'
        }

        /**#@-*/
    },

    glider: {
        label:{}
    },

    /* special grid options */
    grid : {
        /**#@+
         * @visprop
         */

        /* grid styles */
        needsRegularUpdate : false,
        hasGrid : false,
        gridX : 1,
        gridY : 1,
        strokeColor : '#C0C0C0',
        strokeOpacity : '0.5',
        strokeWidth: 1,
        dash : 0,    // dashed grids slow down the iPad considerably
        /* snap to grid options */
        
        /**
         * @deprecated
         */
        snapToGrid : false,
        /**
         * @deprecated
         */
        snapSizeX : 10,
        /**
         * @deprecated
         */
        snapSizeY : 10

        /**#@-*/
    },

    /* special grid options */
    image : {
        imageString : null,
        fillOpacity: 1.0,
        cssClass : 'JXGimage',
        highlightCssClass : 'JXGimageHighlight',
        rotate: 0
    },
    
    /* special options for incircle of 3 points */
    incircle : {
        fillColor : 'none',
        highlightFillColor : 'none',
        strokeColor : '#0000ff',
        highlightStrokeColor : '#C3D9FF',
        center : {               // center point
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        }
    },

    infobox : {
        /**#@+
         * @visprop
         */

        fontSize : 12,
        isLabel: false,
        strokeColor : '#bbbbbb',
        display : 'html',                    // 'html' or 'internal'
        anchorX: 'left',                     //  'left', 'middle', or 'right': horizontal alignment of the text.
        anchorY: 'middle',                   //  'top', 'middle', or 'bottom': vertical alignment of the text.
        cssClass : 'JXGinfobox',
        rotate: 0,                           // works for non-zero values only in combination with display=='internal'
		visible: true

        /**#@-*/
    },


    /* special options for integral */
    integral: {
        withLabel: true,    // Show integral value as text
        strokeWidth: 0,
        strokeOpacity: 0,
        fillOpacity: 0.8,
        curveLeft: {    // Start point
            visible: true,
            layer: 9
        },
        baseLeft: {    // Start point
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        },
        curveRight: {      // End point
            visible: true,
            layer: 9
        },
        baseRight: {      // End point
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        },
        label: {
            fontSize: 20
        }
    },

    /* special intersection point options */
    intersection: {
        /**#@+
         * @visprop
         */
        /**
         * Used in {@link JXG.Intersection}.
         * This flag sets the behaviour of intersection points of e.g.
         * two segments. If true, the intersection is treated as intersection of lines. If false
         * the intersection point exists if the segments intersect setwise.
         * @name JXG.Intersection.alwaysIntersect
         * @type Boolean
         * @default true       
         */  
         alwaysIntersect: true
        /**#@-*/
    },
    
    /* special legend options */
    label: {
        /**#@+
         * @visprop
         */
        strokeColor : '#552222',
        highlightStrokeOpacity:1,
        highlightStrokeColor: '#C3D9FF',
        
        fixed: true,
        /**
         * Possible string values for the position of a label for
         * label anchor points are:
         * 'lft'|'rt'|'top'|'bot'|'ulft'|'urt'|'llft'|'lrt'
         * This is relevant for non-points: line, circle, curve.
         * @type String
         * @default 'urt'
         * @name JXG.GeometryElement#label.position
         */
        position: 'urt',
        
        /**
        *  Label offset from label anchor 
        *  The label anchor is determined by JXG.GeometryElement#label.position
        * @type Array
        * @default [10,10]
        * @name JXG.GeometryElement#label.offset
        **/
        offset: [10, 10]

        /**#@-*/
    },
        
    /* special legend options */
    legend: {
        /**
         * @visprop
         */
        style: 'vertical',
        labels: ['1','2','3','4','5','6','7','8'],
        colors: ['#B02B2C','#3F4C6B','#C79810','#D15600','#FFFF88','#C3D9FF','#4096EE','#008C00']
    },

    /* special line options */
    line : {
        /**#@+
         * @visprop
         */

        firstArrow : false,
        lastArrow : false,
        straightFirst : true,
        straightLast : true,
        fillColor : 'none',               // Important for VML on IE
        highlightFillColor : 'none',  // Important for VML on IE
        strokeColor : '#0000ff',
        highlightStrokeColor : '#888888',
        withTicks: false,

        /**#@-*/

        point1 : {                  // Default values for point1 if created by line
            visible: false, 
            withLabel: false, 
            fixed: false,
            name: ''
        },
        point2 : {                  // Default values for point2 if created by line
            visible: false, 
            withLabel: false, 
            fixed: false,
            name: ''
        },
        ticks : {
            drawLabels : true,
            label: { 
                offset: [4,-12+3] // This seems to be a good offset for 12 point fonts
            },
            drawZero : false,
            insertTicks : false,
            minTicksDistance : 50,
            maxTicksDistance : 300,
            minorHeight : 4,          // if <0: full width and height
            majorHeight : -1,         // if <0: full width and height
            minorTicks : 4,
            defaultDistance : 1,
            strokeOpacity : 0.3
        },
        
        label: {
            position:'llft'
        }
    },

    /* special options for locus curves */
    locus : {
        /**#@+
         * @visprop
         */

        translateToOrigin: false,
        translateTo10: false,
        stretch: false,
        toOrigin: null,
        to10: null

        /**#@-*/
    },
    
    /* special options for normal lines */
    normal : {
        strokeColor: '#000000', //  normal line
        point : {
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        }
    },

    /* special options for orthogonal projectionn points */
    orthogonalprojection : {
    }, 
    
    /* special options for parallel lines */
    parallel : {
        strokeColor: '#000000', // Parallel line
        point : {
            visible: false,
            fixed: false,
            withLabel: false,
            name: ''
        }
    },

    /* special perpendicular options */
    perpendicular : {
        strokeColor: '#000000', // Perpendicular line
        straightFirst: true,
        straightLast: true
    },

    /* special perpendicular options */
    perpendicularsegment : {
        strokeColor: '#000000', // Perpendicular segment
        straightFirst: false,
        straightLast: false,
        point : {               // Perpendicular point
            visible: false,
            fixed: true,
            withLabel: false,
            name: ''
        }
    },

    /* special point options */
    point : {
        /**#@+
         * @visprop
         */

    	withLabel: true,
        label: {},

        /**
         * This attribute was used to determined the point layout. It was derived from GEONExT and was
         * replaced by {@link JXG.Point#face} and {@link JXG.Point#size}.
         * @see JXG.Point#face
         * @see JXG.Point#size
         * @type Number
         * @default JXG.Options.point#style
         * @name JXG.Point#style
         * @deprecated
         */
        style : 5,

        /**
         * There are different point styles which differ in appearance.
         * Posssible values are
         * <table><tr><th>Value</th></tr>
         * <tr><td>cross</td></tr>
         * <tr><td>circle</td></tr>
         * <tr><td>square</td></tr>
         * <tr><td>plus</td></tr>
         * <tr><td>diamond</td></tr>
         * <tr><td>triangleUp</td></tr>
         * <tr><td>triangleDown</td></tr>
         * <tr><td>triangleLeft</td></tr>
         * <tr><td>triangleRight</td></tr>
         * </table>
         * @type string
         * @see JXG.Point#setStyle
         * @default circle
         * @name JXG.Point#face
         */
        face : 'o',

        /**
         * Determines the size of a point.
         * Means radius resp. half the width of a point (depending on the face).
         * @see JXG.Point#face
         * @type number
         * @see JXG.Point#setStyle
         * @default 3
         * @name JXG.Point#size
         */
        size : 3,
        fillColor : '#ff0000',
        highlightFillColor : '#EEEEEE',
        strokeWidth: 2,
        strokeColor : '#ff0000',
        highlightStrokeColor : '#C3D9FF',
        zoom: false,             // Change the point size on zoom

        /**
         * If true, the infobox is shown on mouse over, else not.
         * @name JXG.Point#showInfobox
         * @type Boolean
         * @default true
         */
        showInfobox: true,

        /**
         * Truncating rule for the digits in the infobox.
         * 'auto': done automatically by JXG#autoDigits
         * 'none': no truncation
         * number: use String.toFixed();
         * @name JXG.Point#showInfobox
         * @type String, Number
         * @default true
         */
        infoboxDigits: 'auto',

        draft: false,
        
        /**
         * List of attractor elements. If the distance of the point is less than
         * attractorDistance the point is made to glider of this element.
         * @type array
         * @name JXG.Point#attractors
         * @default empty
         */
        attractors: [],
        
        /**
         * If the distance of the point to one of its attractors is less 
         * than this number the point will be a glider on this 
         * attracting element. 
         * If set to zero nothing happens.
         * @type number
         * @name JXG.Point#attractorDistance
         * @default 0
         */
        attractorDistance: 0.0,
        
        /**
         * If the distance of the point to one of its attractors is at least 
         * this number the point will be released from being a glider on the
         * attracting element. 
         * If set to zero nothing happens.
         * @type number
         * @name JXG.Point#snatchDistance
         * @default 0
         */
        snatchDistance: 0.0,
        
        /**
         * If set to true, the point will snap to a grid defined by
         * {@link JXG.Point#snapSizeX} and {@link JXG.Point#snapSizeY}.
         * @see JXG.Point#snapSizeX
         * @see JXG.Point#snapSizeY
         * @type Boolean
         * @name JXG.Point#snapToGrid
         * @default false
         */
        snapToGrid: false,

        /**
         * Defines together with {@link JXG.Point#snapSizeY} the grid the point snaps on to.
         * The point will only snap on values multiple to snapSizeX in x and snapSizeY in y direction.
         * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks
         * of the default ticks of the default x axes of the board.
         * @see JXG.Point#snapToGrid
         * @see JXG.Point#snapSizeY
         * @see JXG.Board#defaultAxes
         * @type Number
         * @name JXG.Point#snapSizeX
         * @default 1
         */
        snapSizeX: 1,

        /**
         * Defines together with {@link JXG.Point#snapSizeX} the grid the point snaps on to.
         * The point will only snap on values multiple to snapSizeX in x and snapSizeY in y direction.
         * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks
         * of the default ticks of the default y axes of the board.
         * @see JXG.Point#snapToGrid
         * @see JXG.Point#snapSizeX
         * @see JXG.Board#defaultAxes
         * @type Number
         * @name JXG.Point#snapSizeY
         * @default 1
         */
        snapSizeY: 1,

        /**
         * If set to true, the point will snap to the nearest point in distance of 
         * {@link JXG.Point#attractorDistance}.
         * @see JXG.Point#attractorDistance
         * @type Boolean
         * @name JXG.Point#snapToPoints
         * @default false
         */
        snapToPoints: false

        /**#@-*/
    },

    /* special polygon options */
    polygon : {
        /**#@+
         * @visprop
         */

        /**
         * If <tt>true</tt>, moving the mouse over inner points triggers hasPoint.
         * @see JXG.GeometryElement#hasPoint
         * @name JXG.Polygon#hasInnerPoints
         * @type Boolean
         * @default false
         */
        hasInnerPoints: false,
        fillColor : '#00FF00',
        highlightFillColor : '#00FF00',
        fillOpacity : 0.3,
        highlightFillOpacity : 0.3,

        /**
         * Is the polygon bordered by lines?
         * @type Boolean
         * @name JXG.Polygon#withLines
         * @default true
         */
        withLines: true,

        /**#@-*/

        borders: {
            withLabel: false,
		    strokeWidth: 1,
		    highlightStrokeWidth: 1,
            // Polygon layer + 1
            layer: 5
        },
        
        /**
         *  Points for regular polygons
         */ 
        vertices : {
            withLabel: true,
            strokeColor: '#ff0000',
            fillColor: '#ff0000',
            fixed: true
        },
        
        label: {
            offset: [0,0]
        }
    },

    /* special prescribed angle options */
    prescribedangle : {
        anglepoint: {
            size: 2,
            visible: false,
            withLabel: false
        }
    },
    
    /* special options for riemann sums */
    riemannsum: {
        withLabel:false,
        fillOpacity:0.3,
        fillColor:'#ffff00'
    },

    /* special sector options */
    sector : {
        fillColor: '#00FF00',
        highlightFillColor: '#00FF00',
        fillOpacity: 0.3,
        highlightFillOpacity: 0.3,
        label: {
            offset:[0,0]
        }
    },

    /* special segment options */
    segment: {
        label: {
            position: 'top'
        }
    },
    
    semicircle : {
        midpoint: {
            visible: false,
            withLabel: false,
            fixed: false,
            name: ''
        }
    },

    /* special slider options */
    slider : {
        /**#@+
         * @visprop
         */

        /**
         * The slider only returns multiples of this value, e.g. for discrete values set this property to <tt>1</tt>. For
         * continuous results set this to <tt>-1</tt>.
         * @memberOf Slider.prototype
         * @name snapWidth
         * @type Number
         */
        snapWidth: -1,      // -1 = deactivated

        /**
         * The precision of the slider value displayed in the optional text.
         * @memberOf Slider.prototype
         * @name precision
         * @type Number
         */
        precision: 2,
        firstArrow : false,
        lastArrow : false,
        withTicks: true,
        withLabel: true,

        layer: 9,
        showInfobox: false,
        name : '',
        visible: true,
        strokeColor : '#000000',
        highlightStrokeColor : '#888888',
        fillColor : '#ffffff',
        highlightFillColor : 'none',
        size: 6,

        /**#@-*/
            
        point1: {
            needsRegularUpdate : false,
            showInfobox: false,
            withLabel: false,
            visible: false,
            fixed: true,
            name: ''
        },
        point2: {
            needsRegularUpdate : false,
            showInfobox: false,
            withLabel: false,
            visible: false,
            fixed: true,
            name: ''
        },
        baseline: {
            needsRegularUpdate : false,
            name : '',
            strokeWidth: 1,
            strokeColor : '#000000',
            highlightStrokeColor : '#888888'
        },
        /* line ticks options */
        ticks : {
            needsRegularUpdate : false,
            drawLabels : false,
            drawZero : true,
            insertTicks : true,
            minorHeight : 4,          // if <0: full width and height
            majorHeight : 10,        // if <0: full width and height
            minorTicks : 0,
            defaultDistance : 1,
            strokeOpacity : 1,
            strokeWidth: 1,
            strokeColor : '#000000'
        }, 
        highline: {
            strokeWidth: 3,
            name : '',
            strokeColor : '#000000',
            highlightStrokeColor : '#888888'
        },
        label: {
            strokeColor: '#000000'
        }
    },
    
    /* special text options */
    text : {
        /**#@+
         * @visprop
         */

        fontSize : 12,
        digits: 2,
        isLabel: false,
        strokeColor : '#552222',
        useASCIIMathML : false,
        useMathJax : false,
        display : 'html',                    // 'html' or 'internal'
        anchorX: 'left',                     //  'left', 'middle', or 'right': horizontal alignment of the text.
        anchorY: 'middle',                     //  'top', 'middle', or 'bottom': vertical alignment of the text.
        cssClass : 'JXGtext',
        highlightCssClass : 'JXGtext',
        withLabel: false,
        rotate: 0,                        // works for non-zero values only in combination with display=='internal'
		visible: true

        /**#@-*/
    },
    
    /* special options for trace curves */
    tracecurve : {
        /**#@+
         * @visprop
         */
        strokeColor: '#000000',
        fillColor: 'none',
        numberPoints: 100

        /**#@-*/
    },

    /*special turtle options */
    turtle : {
        strokeWidth : 1,
		fillColor: 'none',
		strokeColor: '#000000',
		arrow : {
			strokeWidth: 2,
			withLabel: false,
			strokeColor: '#ff0000'
		}
    },


    /**
      * Abbreviations of properties. Setting the shortcut means setting abbreviated properties
      * to the same value.
      * It is used in JXG.GeometryElement#setProperty and in
      * the constructor JXG.GeometryElement.
      * Attention: In Options.js abbreviations are not allowed.
      */
    shortcuts : {
        color: ['strokeColor', 'fillColor'],
        opacity: ['strokeOpacity', 'fillOpacity'],
        highlightColor: ['highlightStrokeColor', 'highlightFillColor'],
        highlightOpacity: ['highlightStrokeOpacity', 'highlightFillOpacity'],
        strokeWidth: ['strokeWidth', 'highlightStrokeWidth']
    }
    
};

/**
 * Holds all possible properties and the according validators for geometry elements. A validator is either a function
 * which takes one parameter and returns true, if the value is valid for the property, or it is false if no validator
 * is required.
 */
JXG.Validator = (function () {
    var validatePixel = function (v) {
            return /^[0-9]+px$/.test(v);
        },
        validateDisplay = function (v) {
            return (v  in {html: 0, internal: 0});
        },
        validateColor = function (v) {
            // for now this should do it...
            return JXG.isString(v);
        },
        validatePointFace = function (v) {
            return JXG.exists(JXG.Point.prototype.normalizeFace.call(this, v));
        },
        validateInteger = function (v) {
            return (Math.abs(v - Math.round(v)) < JXG.Math.eps);
        },
        validatePositiveInteger = function (v) {
            return validateInteger(v) && v > 0;
        },
        validateScreenCoords = function (v) {
            return v.length >= 2 && validateInteger(v[0]) && validateInteger(v[1]);
        },
        validateRenderer = function (v) {
            return (v in {vml: 0, svg: 0, canvas: 0});
        },
        validatePositive = function (v) {
            return v > 0;
        },
        validateNotNegative = function (v) {
            return !(v < 0);
        },
    i, v = {},
    validators = {
        attractorDistance: validateNotNegative,
        color: validateColor,
        defaultDistance: JXG.isNumber,
        display : validateDisplay,
        doAdvancedPlot: false,
        draft : false,
        drawLabels : false,
        drawZero : false,
        face : validatePointFace,
        factor : JXG.isNumber,
        fillColor: validateColor,
        fillOpacity : JXG.isNumber,
        firstArrow : false,
        fontSize : validateInteger,
        dash : validateInteger,
        gridX : JXG.isNumber,
        gridY : JXG.isNumber,
        hasGrid : false,
        highlightFillColor: validateColor,
        highlightFillOpacity: JXG.isNumber,
        highlightStrokeColor: validateColor,
        highlightStrokeOpacity: JXG.isNumber,
        insertTicks : false,
        //: validateScreenCoords,
        lastArrow : false,
        majorHeight : validateInteger,
        maxTicksDistance : validatePositiveInteger,
        minorHeight : validateInteger,
        minorTicks : validatePositiveInteger,
        minTicksDistance : validatePositiveInteger,
        numberPointsHigh : validatePositiveInteger,
        numberPointsLow : validatePositiveInteger,
        opacity : JXG.isNumber,
        radius : JXG.isNumber,
        RDPsmoothing : false,
        renderer: validateRenderer,
        right: validatePixel,
        showCopyright : false,
        showInfobox: false,
        showNavigation : false,
        size : validateInteger,
        snapSizeX : validatePositive,
        snapSizeY : validatePositive,
        snapWidth : JXG.isNumber,
        snapToGrid : false,
        snatchDistance: validateNotNegative,
        straightFirst : false,
        straightLast : false,
        stretch: false,
        strokeColor : validateColor,
        strokeOpacity: JXG.isNumber,
        strokeWidth : validateInteger,
        takeFirst : false,
        takeSizeFromFile : false,
        to10: false,
        toOrigin: false,
        translateTo10: false,
        translateToOrigin: false,
        useASCIIMathML : false,
        useDirection: false,
        useMathJax : false,
        withLabel: false,
        withTicks: false,
        zoom: false
    };

    // this seems like a redundant step but it makes sure that
    // all properties in the validator object have lower case names
    // and the validator object is easier to read.
    for (i in validators) {
        v[i.toLowerCase()] = validators[i];
    }

    return v;
})();


/**
 * Apply the options stored in this object to all objects on the given board.
 * @param {JXG.Board} board The board to which objects the options will be applied.
 */
JXG.useStandardOptions = function(board) {
    var o = JXG.Options,
        boardHadGrid = board.hasGrid,
        el, t, p, copyProps;

    board.options.grid.hasGrid = o.grid.hasGrid;
    board.options.grid.gridX = o.grid.gridX;
    board.options.grid.gridY = o.grid.gridY;
    board.options.grid.gridColor = o.grid.gridColor;
    board.options.grid.gridOpacity = o.grid.gridOpacity;
    board.options.grid.gridDash = o.grid.gridDash;
    board.options.grid.snapToGrid = o.grid.snapToGrid;
    board.options.grid.snapSizeX = o.grid.SnapSizeX;
    board.options.grid.snapSizeY = o.grid.SnapSizeY;
    board.takeSizeFromFile = o.takeSizeFromFile;

    copyProps = function(p, o) {
            p.visProp.fillcolor = o.fillColor;
            p.visProp.highlightfillcolor = o.highlightFillColor;
            p.visProp.strokecolor = o.strokeColor;
            p.visProp.highlightstrokecolor = o.highlightStrokeColor;
    };
    
    for(el in board.objects) {
        p = board.objects[el];
        if(p.elementClass == JXG.OBJECT_CLASS_POINT) {
            copyProps(p, o.point);
        }
        else if(p.elementClass == JXG.OBJECT_CLASS_LINE) {
            copyProps(p, o.line);
            for(t in p.ticks) {
                t.majorTicks = o.line.ticks.majorTicks;
                t.minTicksDistance = o.line.ticks.minTicksDistance;
                t.visProp.minorheight = o.line.ticks.minorHeight;
                t.visProp.majorheight = o.line.ticks.majorHeight;
            }
        }
        else if(p.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
            copyProps(p, o.circle);
        }
        else if(p.type == JXG.OBJECT_TYPE_ANGLE) {
            copyProps(p, o.angle);
        }
        else if(p.type == JXG.OBJECT_TYPE_ARC) {
            copyProps(p, o.arc);
        }
        else if(p.type == JXG.OBJECT_TYPE_POLYGON) {
            copyProps(p, o.polygon);
        }
        else if(p.type == JXG.OBJECT_TYPE_CONIC) {
            copyProps(p, o.conic);
        }
        else if(p.type == JXG.OBJECT_TYPE_CURVE) {
            copyProps(p, o.curve);
        }
        else if(p.type == JXG.OBJECT_TYPE_SECTOR) {
            p.arc.visProp.fillcolor = o.sector.fillColor;
            p.arc.visProp.highlightfillcolor = o.sector.highlightFillColor;
            p.arc.visProp.fillopacity = o.sector.fillOpacity;
            p.arc.visProp.highlightfillopacity = o.sector.highlightFillOpacity;
        }
    }

    board.fullUpdate();
    if(boardHadGrid && !board.hasGrid) {
        board.removeGrids(board);
    } else if(!boardHadGrid && board.hasGrid) {
        board.create('grid', []);
    }
};

/**
 * Converts all color values to greyscale and calls useStandardOption to put them onto the board.
 * @param {JXG.Board} board The board to which objects the options will be applied.
 * @see #useStandardOptions
 */
JXG.useBlackWhiteOptions = function(board) {
    var o = JXG.Options;
    o.point.fillColor = JXG.rgb2bw(o.point.fillColor);
    o.point.highlightFillColor = JXG.rgb2bw(o.point.highlightFillColor);
    o.point.strokeColor = JXG.rgb2bw(o.point.strokeColor);
    o.point.highlightStrokeColor = JXG.rgb2bw(o.point.highlightStrokeColor);

    o.line.fillColor = JXG.rgb2bw(o.line.fillColor);
    o.line.highlightFillColor = JXG.rgb2bw(o.line.highlightFillColor);
    o.line.strokeColor = JXG.rgb2bw(o.line.strokeColor);
    o.line.highlightStrokeColor = JXG.rgb2bw(o.line.highlightStrokeColor);

    o.circle.fillColor = JXG.rgb2bw(o.circle.fillColor);
    o.circle.highlightFillColor = JXG.rgb2bw(o.circle.highlightFillColor);
    o.circle.strokeColor = JXG.rgb2bw(o.circle.strokeColor);
    o.circle.highlightStrokeColor = JXG.rgb2bw(o.circle.highlightStrokeColor);

    o.arc.fillColor = JXG.rgb2bw(o.arc.fillColor);
    o.arc.highlightFillColor = JXG.rgb2bw(o.arc.highlightFillColor);
    o.arc.strokeColor = JXG.rgb2bw(o.arc.strokeColor);
    o.arc.highlightStrokeColor = JXG.rgb2bw(o.arc.highlightStrokeColor);

    o.polygon.fillColor = JXG.rgb2bw(o.polygon.fillColor);
    o.polygon.highlightFillColor  = JXG.rgb2bw(o.polygon.highlightFillColor);

    o.sector.fillColor = JXG.rgb2bw(o.sector.fillColor);
    o.sector.highlightFillColor  = JXG.rgb2bw(o.sector.highlightFillColor);

    o.curve.strokeColor = JXG.rgb2bw(o.curve.strokeColor);
    o.grid.gridColor = JXG.rgb2bw(o.grid.gridColor);

    JXG.useStandardOptions(board);
};


/*
    Copyright 2008-2012
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/


/*global JXG:true*/

/**
 * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards.
 * It has methods to create, save, load and free boards. Additionally some helper functions are
 * defined in this file directly in the JXG namespace.
 * @version 0.97
 */


'use strict';

/**
 * Constructs a new JSXGraph singleton object.
 * @class The JXG.JSXGraph singleton stores all properties required
 * to load, save, create and free a board.
 */
JXG.JSXGraph = {

    /**
     * The small gray version indicator in the top left corner of every JSXGraph board (if
     * showCopyright is not set to false on board creation).
     * @type String
     */
    licenseText: 'JSXGraph v0.97.1 Copyright (C) see http://jsxgraph.org',

    /**
     * Associative array that keeps references to all boards.
     * @type Object
     */
    boards: {},

    /**
     * Associative array that keeps track of all constructable elements registered
     * via {@link JXG.JSXGraph.registerElement}.
     * @type Object
     */
    elements: {},

    /**
     * Stores the renderer that is used to draw the boards.
     * @type String
     */
    rendererType: (function() {
        var loadRenderer = function (renderer) {
            var arr, i;

            // Load the source files for the renderer
            if (JXG.rendererFiles[renderer]) {
                arr = JXG.rendererFiles[renderer].split(',');

                for (i = 0; i < arr.length; i++) {
                    (function(include) {
                        JXG.require(JXG.requirePath + include + '.js');
                    }(arr[i]));
                }

                delete(JXG.rendererFiles[renderer]);
            }
        };

        JXG.Options.renderer = 'no';

        if (JXG.supportsVML()) {
            JXG.Options.renderer = 'vml';
            // Ok, this is some real magic going on here. IE/VML always was so
            // terribly slow, except in one place: Examples placed in a moodle course
            // was almost as fast as in other browsers. So i grabbed all the css and
            // lib scripts from our moodle, added them to a jsxgraph example and it
            // worked. next step was to strip all the css/lib code which didn't affect
            // the VML update speed. The following five lines are what was left after
            // the last step and yes - it basically does nothing but reads two
            // properties of document.body on every mouse move. why? we don't know. if
            // you know, please let us know.
            //
            // If we want to use the strict mode we have to refactor this a little bit. Let's
            // hope the magic isn't gone now. Anywho... it's only useful in old versions of IE
            // which should not be used anymore.
            document.onmousemove = function () {
                var t;

                if (document.body) {
                    t = document.body.scrollLeft;
                    t = document.body.scrollTop;
                }
            };
            loadRenderer('vml');
        }

        if (JXG.supportsCanvas()) {
            JXG.Options.renderer = 'canvas';
            loadRenderer('canvas');
        }

        if (JXG.supportsSVG()) {
            JXG.Options.renderer = 'svg';
            loadRenderer('svg');
        }
        
        // we are inside node
        if (JXG.isNode()) {
            JXG.Options.renderer = 'canvas';
            loadRenderer('canvas');
        }

        return JXG.Options.renderer;
    }()),
    
    initRenderer: function (box) {
        var boxid, renderer;
        
        if (typeof document === 'object' && box !== null) {
            boxid = document.getElementById(box);
        } else {
            boxid = box;
        }
    
        // create the renderer
        if(JXG.Options.renderer === 'svg') {
            renderer = new JXG.SVGRenderer(boxid);
        } else if(JXG.Options.renderer === 'vml') {
            renderer = new JXG.VMLRenderer(boxid);
        } else if (JXG.Options.renderer === 'canvas') {
            renderer = new JXG.CanvasRenderer(boxid);
        } else {
            renderer = new JXG.NoRenderer();
        }
        
        return renderer;
    },

    /**
     * Initialise a new board.
     * @param {String} box Html-ID to the Html-element in which the board is painted.
     * @param {Object} attributes An object that sets some of the board properties. Most of these properties can be set via JXG.Options. Valid properties are
     * <ul>
     *     <li><b>boundingbox</b>: An array containing four numbers describing the left, top, right and bottom boundary of the board in user coordinates</li>
     *     <li><b>keepaspectratio</b>: If <tt>true</tt>, the bounding box is adjusted to the same aspect ratio as the aspect ratio of the div containing the board.</li>
     *     <li><b>showCopyright</b>: Show the copyright string in the top left corner.</li>
     *     <li><b>showNavigation</b>: Show the navigation buttons in the bottom right corner.</li>
     *     <li><b>zoom</b>: Allow the user to zoom with the mouse wheel or the two-fingers-zoom gesture.</li>
     *     <li><b>pan</b>: Allow the user to pan with shift+drag mouse or two-fingers-pan gesture.</li>
     *     <li><b>axis</b>: If set to true, show the axis. Can also be set to an object that is given to both axes as an attribute object.</li>
     *     <li><b>grid</b>: If set to true, shows the grid. Can also bet set to an object that is given to the grid as its attribute object.</li>
     * </ul>
     * @returns {JXG.Board} Reference to the created board.
     */
    initBoard: function (box, attributes) {
        var renderer,
            originX, originY, unitX, unitY,
            w, h, dimensions,
            bbox,
            zoomfactor, zoomX, zoomY,
            showCopyright, showNavi,
            board,
            wheelzoom, shiftpan, attr;

        dimensions = JXG.getDimensions(box);
        
        // parse attributes
        if (typeof attributes === 'undefined') {
            attributes = {};
        }

        if (typeof attributes["boundingbox"] != 'undefined') {
            bbox = attributes["boundingbox"];
            w = parseInt(dimensions.width);
            h = parseInt(dimensions.height);

            if (attributes["keepaspectratio"]) {
                /*
                 * If the boundingbox attribute is given and the ratio of height and width of the
                 * sides defined by the bounding box and the ratio of the dimensions of the div tag
                 * which contains the board do not coincide, then the smaller side is chosen.
                 */
                unitX = w/(bbox[2]-bbox[0]);
                unitY = h/(-bbox[3]+bbox[1]);
                if (Math.abs(unitX)<Math.abs(unitY)) {
                    unitY = Math.abs(unitX)*unitY/Math.abs(unitY);
                } else {
                    unitX = Math.abs(unitY)*unitX/Math.abs(unitX);
                }
            } else {
                unitX = w/(bbox[2]-bbox[0]);
                unitY = h/(-bbox[3]+bbox[1]);
            }
            originX = -unitX*bbox[0];
            originY = unitY*bbox[1];
        } else {
            originX = ( (typeof attributes["originX"]) == 'undefined' ? 150 : attributes["originX"]);
            originY = ( (typeof attributes["originY"]) == 'undefined' ? 150 : attributes["originY"]);
            unitX = ( (typeof attributes["unitX"]) == 'undefined' ? 50 : attributes["unitX"]);
            unitY = ( (typeof attributes["unitY"]) == 'undefined' ? 50 : attributes["unitY"]);
        }

        zoomfactor = ( (typeof attributes["zoomfactor"]) == 'undefined' ? 1.0 : attributes["zoom"]);
        zoomX = zoomfactor*( (typeof attributes["zoomX"]) == 'undefined' ? 1.0 : attributes["zoomX"]);
        zoomY = zoomfactor*( (typeof attributes["zoomY"]) == 'undefined' ? 1.0 : attributes["zoomY"]);

        showCopyright = ( (typeof attributes["showCopyright"]) == 'undefined' ? JXG.Options.showCopyright : attributes["showCopyright"]);

        wheelzoom = ( (typeof attributes["zoom"]) == 'undefined' ? JXG.Options.zoom.wheel : attributes["zoom"]);
        shiftpan = ( (typeof attributes["pan"]) == 'undefined' ? JXG.Options.pan : attributes["pan"]);

        renderer = this.initRenderer(box);

        // create the board
        board = new JXG.Board(box, renderer, '', [originX, originY], zoomX, zoomY, unitX, unitY, dimensions.width, dimensions.height, showCopyright);
        this.boards[board.id] = board;

        board.keepaspectratio = attributes.keepaspectratio;
        board.options.zoom.wheel = wheelzoom;
        board.options.pan = shiftpan;

        // create elements like axes, grid, navigation, ...
        board.suspendUpdate();
        board.initInfobox();
        
        if(attributes["axis"]) {
            attr = typeof attributes['axis'] === 'object' ? attributes['axis'] : {ticks: {drawZero: true}};
        	board.defaultAxes = {};
            board.defaultAxes.x = board.create('axis', [[0,0], [1,0]], attr);
            board.defaultAxes.y = board.create('axis', [[0,0], [0,1]], attr);
        }

        if(attributes["grid"]) {
            board.create('grid', [], (typeof attributes["grid"] === 'object' ? attributes['grid'] : {}));
        }

        if (typeof attributes["shownavigation"] != 'undefined') attributes["showNavigation"] = attributes["shownavigation"];
        showNavi = ( (typeof attributes["showNavigation"]) == 'undefined' ? board.options.showNavigation : attributes["showNavigation"]);
        if (showNavi) {
            board.renderer.drawZoomBar(board);
        }
        board.unsuspendUpdate();

        return board;
    },

    /**
     * Load a board from a file containing a construction made with either GEONExT,
     * Intergeo, Geogebra, or Cinderella.
     * @param {String} box HTML-ID to the HTML-element in which the board is painted.
     * @param {String} file base64 encoded string.
     * @param {String} format containing the file format: 'Geonext' or 'Intergeo'.
     * @returns {JXG.Board} Reference to the created board.
     *
     * @see JXG.FileReader
     * @see JXG.GeonextReader
     * @see JXG.GeogebraReader
     * @see JXG.IntergeoReader
     * @see JXG.CinderellaReader
     */
    loadBoardFromFile: function (box, file, format) {
        var renderer, board, dimensions;

        renderer = this.initRenderer(box);

        //var dimensions = document.getElementById(box).getDimensions();
        dimensions = JXG.getDimensions(box);

        /* User default parameters, in parse* the values in the gxt files are submitted to board */
        board = new JXG.Board(box, renderer, '', [150, 150], 1.0, 1.0, 50, 50, dimensions.width, dimensions.height);
        board.initInfobox();

        JXG.FileReader.parseFileContent(file, board, format);
        if(board.options.showNavigation) {
            board.renderer.drawZoomBar(board);
        }
        this.boards[board.id] = board;
        return board;
    },

    /**
     * Load a board from a base64 encoded string containing a construction made with either GEONExT,
     * Intergeo, Geogebra, or Cinderella.
     * @param {String} box HTML-ID to the HTML-element in which the board is painted.
     * @param {String} string base64 encoded string.
     * @param {String} format containing the file format: 'Geonext' or 'Intergeo'.
     * @returns {JXG.Board} Reference to the created board.
     *
     * @see JXG.FileReader
     * @see JXG.GeonextReader
     * @see JXG.GeogebraReader
     * @see JXG.IntergeoReader
     * @see JXG.CinderellaReader
     */
    loadBoardFromString: function(box, string, format) {
        var renderer, dimensions, board;

        renderer = this.initRenderer(box);
        //var dimensions = document.getElementById(box).getDimensions();
        dimensions = JXG.getDimensions(box);

        /* User default parameters, in parse* the values in the gxt files are submitted to board */
        board = new JXG.Board(box, renderer, '', [150, 150], 1.0, 1.0, 50, 50, dimensions.width, dimensions.height);
        board.initInfobox();

        JXG.FileReader.parseString(string, board, format, true);
        if (board.options.showNavigation) {
            board.renderer.drawZoomBar(board);
        }

        this.boards[board.id] = board;
        return board;
    },

    /**
     * Delete a board and all its contents.
     * @param {String} board HTML-ID to the DOM-element in which the board is drawn.
     */
    freeBoard: function (board) {
        var el, i;

        if (typeof(board) == 'string') {
            board = this.boards[board];
        }

        board.removeEventHandlers();
        board.suspendUpdate();

        // Remove all objects from the board.
        for(el in board.objects) {
            //board.removeObject(board.objects[el]);
            board.objects[el].remove();
        }

        // Remove all the other things, left on the board, XHTML save
        while (board.containerObj.firstChild) {
            board.containerObj.removeChild(board.containerObj.firstChild);
        }
        // board.containerObj.innerHTML = '';

        // Tell the browser the objects aren't needed anymore
        for(el in board.objects) {
            delete(board.objects[el]);
        }

        // Free the renderer and the algebra object
        delete(board.renderer);
        delete(board.algebra);

        // clear the creator cache
        board.jc.creator.clearCache();
        delete(board.jc);

        // Finally remove the board itself from the boards array
        delete(this.boards[board.id]);
    },

    /**
     * This registers a new construction element to JSXGraph for the construction via the {@link JXG.Board.create}
     * interface.
     * @param {String} element The elements name. This is case-insensitive, existing elements with the same name
     * will be overwritten.
     * @param {Function} creator A reference to a function taking three parameters: First the board, the element is
     * to be created on, a parent element array, and an attributes object. See {@link JXG.createPoint} or any other
     * <tt>JXG.create...</tt> function for an example.
     */
    registerElement: function (element, creator) {
        element = element.toLowerCase();
        this.elements[element] = creator;

        if(JXG.Board.prototype['_' + element])
        	throw new Error("JSXGraph: Can't create wrapper method in JXG.Board because member '_" + element + "' already exists'");
        JXG.Board.prototype['_' + element] = function (parents, attributes) {
        	return this.create(element, parents, attributes);
        };

    },

    /**
     * The opposite of {@link JXG.JSXGraph.registerElement}, it removes a given element from
     * the element list. You probably don't need this.
     * @param {String} element The name of the element which is to be removed from the element list.
     */
    unregisterElement: function (element) {
        delete (this.elements[element.toLowerCase()]);
        delete (JXG.Board.prototype['_' + element.toLowerCase()]);
    }
};


/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

JXG.extend(JXG, {
    // object types
    OBJECT_TYPE_ARC: 1,
    OBJECT_TYPE_ARROW: 2,
    OBJECT_TYPE_AXIS: 3,
    OBJECT_TYPE_AXISPOINT: 4,
    OBJECT_TYPE_TICKS: 5,
    OBJECT_TYPE_CIRCLE: 6,
    OBJECT_TYPE_CONIC: 7,
    OBJECT_TYPE_CURVE: 8,
    OBJECT_TYPE_GLIDER: 9,
    OBJECT_TYPE_IMAGE: 10,
    OBJECT_TYPE_LINE: 11,
    OBJECT_TYPE_POINT: 12,
    OBJECT_TYPE_SLIDER: 13,
    OBJECT_TYPE_CAS: 14,
    OBJECT_TYPE_GXTCAS: 15,
    OBJECT_TYPE_POLYGON: 16,
    OBJECT_TYPE_SECTOR: 17,
    OBJECT_TYPE_TEXT: 18,
    OBJECT_TYPE_ANGLE: 19,
    OBJECT_TYPE_INTERSECTION: 20,
    OBJECT_TYPE_TURTLE: 21,
    OBJECT_TYPE_VECTOR: 22,
    OBJECT_TYPE_OPROJECT: 23,
    OBJECT_TYPE_GRID: 24,
    
    // object classes
    OBJECT_CLASS_POINT: 1,
    OBJECT_CLASS_LINE: 2,
    OBJECT_CLASS_CIRCLE: 3,
    OBJECT_CLASS_CURVE: 4,
    OBJECT_CLASS_AREA: 5,
    OBJECT_CLASS_OTHER: 6    
});

/**
 * Constructs a new GeometryElement object.
 * @class This is the basic class for geometry elements like points, circles and lines.
 * @constructor
 * @param {JXG.Board} board Reference to the board the element is constructed on.
 * @param {Object} attributes Hash of attributes and their values.
 * @param {Number} type Element type (a <tt>JXG.OBJECT_TYPE_</tt> value).
 * @param {oclass} oclass The element's class (a <tt>JXG.OBJECT_CLASS_</tt> value).
 * @borrows JXG.EventEmitter#on as this.on
 * @borrows JXG.EventEmitter#off as this.off
 * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers
 * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers
 */
JXG.GeometryElement = function (board, attributes, type, oclass) {
    var name, key;

    /**
     * Controls if updates are necessary
     * @type Boolean
     * @default true
     */
    this.needsUpdate = true;

    /**
     * Controls if this element can be dragged. In GEONExT only
     * free points and gliders can be dragged.
     * @type Boolean
     * @default false
     */
    this.isDraggable = false;
    
    /**
     * If element is in two dimensional real space this is true, else false.
     * @type Boolean
     * @default true
     */
    this.isReal = true;

    /**
     * Stores all dependent objects to be updated when this point is moved.
     * @type Object
     */
    this.childElements = {};

    /**
     * If element has a label subelement then this property will be set to true.
     * @type Boolean
     * @default false
     */
    this.hasLabel = false;

    /**
     * True, if the element is currently highlighted.
     * @type Boolean
     * @default false
     */
    this.highlighted = false;

    /**
     * Stores all Intersection Objects which in this moment are not real and
     * so hide this element.
     * @type Object
     */
    this.notExistingParents = {};

    /**
     * Keeps track of all objects drawn as part of the trace of the element.
     * @see JXG.GeometryElement#traced
     * @see JXG.GeometryElement#clearTrace
     * @see JXG.GeometryElement#numTraces
     * @type Object
     */
    this.traces = {};

    /**
     * Counts the number of objects drawn as part of the trace of the element.
     * @see JXG.GeometryElement#traced
     * @see JXG.GeometryElement#clearTrace
     * @see JXG.GeometryElement#traces
     * @type Number
     */
    this.numTraces = 0;

    /**
     * Stores the  transformations which are applied during update in an array
     * @type Array
     * @see JXG.Transformation
     */
    this.transformations = [];

    /** TODO
     * @type JXG.GeometryElement
     * @default null
     * @private
     */
    this.baseElement = null;

    /**
     * Elements depending on this element are stored here.
     * @type Object
     */
    this.descendants = {};

    /**
     * Elements on which this elements depends on are stored here.
     * @type Object
     */
    this.ancestors = {};

    /**
     * Stores variables for symbolic computations
     * @type Object
     */
    this.symbolic = {};

    /**
     * The string used with {@link JXG.Board#create}
     * @type String
     */
    this.elType = '';

    /**
     * The element is saved with an explicit entry in the file (<tt>true</tt>) or implicitly
     * via a composition.
     * @type Boolean
     * @default true
     */
    this.dump = true;

    /**
     * Subs contains the subelements, created during the create method.
     * @type Object
     */
    this.subs = {};

    /**
     * The position of this element inside the {@link JXG.Board#objectsList}.
     * @type {Number}
     * @default -1
     * @private
     */
    this._pos = -1;

    /**
     * [c,b0,b1,a,k,r,q0,q1]
     *
     * See
     * A.E. Middleditch, T.W. Stacey, and S.B. Tor:
     * "Intersection Algorithms for Lines and Circles",
     * ACM Transactions on Graphics, Vol. 8, 1, 1989, pp 25-40.
     *
     * The meaning of the parameters is:
     * Circle: points p=[p0,p1] on the circle fulfill
     *  a&lt;p,p&gt; + &lt;b,p&gt; + c = 0
     * For convenience we also store
     *  r: radius
     *  k: discriminant = sqrt(&lt;b,b&gt;-4ac)
     *  q=[q0,q1] center
     *
     * Points have radius = 0.
     * Lines have radius = infinity.
     * b: normalized vector, representing the direction of the line.
     *
     * Should be put into Coords, when all elements possess Coords.
     * @type Array
     * @default [1, 0, 0, 0, 1, 1, 0, 0]
     */
    this.stdform = [1,0,0,0,1, 1,0,0];

    /**
     * The methodMap determines which methods can be called from within JessieCode and under which name it
     * can be used. The map is saved in an object, the name of a property is the name of the method used in JessieCode,
     * the value of a property is the name of the method in JavaScript.
     * @type Object
     */
    this.methodMap = {
        setLabel: 'setLabelText',
        getName: 'getName',
        addTransform: 'addTransform',
        setProperty: 'setProperty',
        setAttribute: 'setAttribute'
    };

    /**
     * Quadratic form representation of circles (and conics)
     * @type Array
     * @default [[1,0,0],[0,1,0],[0,0,1]]
     */
    this.quadraticform = [[1,0,0],[0,1,0],[0,0,1]];

    /**
     * An associative array containing all visual properties.
     * @type Object
     * @default empty object
     */
    this.visProp = {};

    JXG.EventEmitter.eventify(this);
    
    /**
     * Is the mouse over this element?
     * @type Boolean
     * @default false
     */
    this.mouseover = false;

    if (arguments.length > 0) {
        /**
         * Reference to the board associated with the element.
         * @type JXG.Board
         */
        this.board = board;

        /**
         * Type of the element.
         * @constant
         * @type number
         */
        this.type = type;

        /**
         * The element's class.
         * @constant
         * @type number
         */
        this.elementClass = oclass || JXG.OBJECT_CLASS_OTHER;

        /**
         * Unique identifier for the element. Equivalent to id-attribute of renderer element.
         * @type String
         */
        this.id = attributes.id;

        name = attributes.name;
        /* If name is not set or null or even undefined, generate an unique name for this object */
        if (!JXG.exists(name)) {
            name = this.board.generateName(this);
        }
        this.board.elementsByName[name] = this;

        /**
         * Not necessarily unique name for the element.
         * @type String
         * @default Name generated by {@link JXG.Board#generateName}.
         * @see JXG.Board#generateName
         */
        this.name = name;

        this.needsRegularUpdate = attributes.needsregularupdate;

        JXG.clearVisPropOld(this); // create this.visPropOld and set default values

        attributes = this.resolveShortcuts(attributes);
        for (key in attributes) {
            this._set(key, attributes[key]);
        }

        // TODO: draft downwards compatibility.
        this.visProp.draft = attributes.draft && attributes.draft.draft;

        this.visProp.gradientangle = '270';
        this.visProp.gradientsecondopacity = this.visProp.fillopacity;
        this.visProp.gradientpositionx = 0.5;
        this.visProp.gradientpositiony = 0.5;
    }
};

JXG.extend(JXG.GeometryElement.prototype, /** @lends JXG.GeometryElement.prototype */ {
    /**
     * Add an element as a child to the current element. Can be used to model dependencies between geometry elements.
     * @param {JXG.GeometryElement} obj The dependent object.
     */
    addChild: function (obj) {
        var el, el2;

        this.childElements[obj.id] = obj;

        this.addDescendants(obj);

        obj.ancestors[this.id] = this;
        for (el in this.descendants) {
            this.descendants[el].ancestors[this.id] = this;
            for (el2 in this.ancestors) {
                this.descendants[el].ancestors[this.ancestors[el2].id] = this.ancestors[el2];
            }
        }
        for (el in this.ancestors) {
            for (el2 in this.descendants) {
                this.ancestors[el].descendants[this.descendants[el2].id] = this.descendants[el2];
            }
        }
        return this;
    },

    /**
     * Adds the given object to the descendants list of this object and all its child objects.
     * @param {JXG.GeometryElement} obj The element that is to be added to the descendants list.
     * @private
     * @return
     */
    addDescendants: function (obj) {
        var el;

        this.descendants[obj.id] = obj;
        for (el in obj.childElements) {
            this.addDescendants(obj.childElements[el]);
        }
        return this;
    },
    
    /**
     * Counts the direct children of an object without counting labels.
     * @private
     * @return {number} Number of children
     */
    countChildren: function () {
        var prop, s=0, d;

        d = this.childElements;
        for (prop in d) {
            if (d.hasOwnProperty(prop) && prop.indexOf('Label')<0) {
                s++;
            }
        }
        return s; 
    },

    /**
     * Returns the elements name, Used in JessieCode.
     * @returns {String}
     */
    getName: function () {
        return this.name;
    },
    
    /**
     * Add transformations to this element.
     * @param {JXG.Transform|Array} transform Either one {@link JXG.Transform} or an array of {@link JXG.Transform}s.
     * @returns {JXG.Curve} Reference to the element.
     */
    addTransform: function () {},
    
    /**
     * Decides whether an element can be dragged. This is used in setPositionDirectly methods
     * where all parent elements are checked if they may be dragged, too.
     * @private
     * @return {boolean}
     */
    draggable: function() {
        return this.isDraggable 
               && !this.visProp.fixed 
               && !this.visProp.frozen 
               && this.type != JXG.OBJECT_TYPE_GLIDER;    // Experimentally turned off
               // && this.countChildren() <= 1;            // Experimentally turned off
    },
    
    /**
     * Array of strings containing the polynomials defining the element.
     * Used for determining geometric loci the groebner way.
     * @type Array
     * @return An array containing polynomials describing the locus of the current object.
     * @private
     */
    generatePolynomial: function () {
        return [];
    },

    /**
     * Animates properties for that object like stroke or fill color, opacity and maybe
     * even more later.
     * @param {Object} hash Object containing propiertes with target values for the animation.
     * @param {number} time Number of milliseconds to complete the animation.
     * @param {Object} [options] Optional settings for the animation:<ul><li>callback: A function that is called as soon as the animation is finished.</li></ul>
     * @return A reference to the object
     * @type JXG.GeometryElement
     */
    animate: function (hash, time, options) {
        options = options || {};
        var r, p,
            delay = this.board.options.animationDelay,
            steps = Math.ceil(time/(delay * 1.0)),
            i, self = this, round = false;

        this.animationData = {};

        var animateColor = function (startRGB, endRGB, property) {
                var hsv1, hsv2, sh, ss, sv;
                hsv1 = JXG.rgb2hsv(startRGB);
                hsv2 = JXG.rgb2hsv(endRGB);

                sh = (hsv2[0]-hsv1[0])/(1.*steps);
                ss = (hsv2[1]-hsv1[1])/(1.*steps);
                sv = (hsv2[2]-hsv1[2])/(1.*steps);
                self.animationData[property] = new Array(steps);
                for (i=0; i<steps; i++) {
                    self.animationData[property][steps-i-1] = JXG.hsv2rgb(hsv1[0]+(i+1)*sh, hsv1[1]+(i+1)*ss, hsv1[2]+(i+1)*sv);
                }
            },
            animateFloat = function (start, end, property, round) {
                var tmp;

                start = parseFloat(start);
                end = parseFloat(end);

                // we can't animate without having valid numbers.
                // And parseFloat returns NaN if the given string doesn't contain
                // a valid float number.
                if (isNaN(start) || isNaN(end))
                    return;

                var s = (end - start)/(1.*steps);
                self.animationData[property] = new Array(steps);
                for (i=0; i<steps; i++) {
                    tmp = start + (i+1)*s;
                    self.animationData[property][steps-i-1] = round ? Math.floor(tmp) : tmp;
                }
            };

        for (r in hash) {
            p = r.toLowerCase();
            switch(p) {
                case 'strokecolor':
                case 'fillcolor':
                    animateColor(this.visProp[p], hash[r], p);
                    break;
                case 'size':
                    if (this.elementClass !== JXG.OBJECT_CLASS_POINT) {
                        break;
                    }
                    round = true;
                case 'strokeopacity':
                case 'strokewidth':
                case 'fillopacity':
                    animateFloat(this.visProp[p], hash[r], p, round);
                    break;
            }
        }

        this.animationCallback = options.callback;
        this.board.addAnimation(this);
        return this;
    },

    /**
     * General update method. Should be overwritten by the element itself.
     * Can be used sometimes to commit changes to the object.
     */
    update: function () {
        if (this.visProp.trace) {
            this.cloneToBackground(true);
        }
        return this;
    },

    /**
     * Provide updateRenderer method.
     * @private
     */
    updateRenderer: function () {
        return this;
    },

    /**
     * Hide the element. It will still exist but not visible on the board.
     */
    hideElement: function () {
        this.visProp.visible = false;
        this.board.renderer.hide(this);

        if (this.label!=null && this.hasLabel) {
            this.label.hiddenByParent = true;
            if (this.label.content.visProp.visible) {
                this.board.renderer.hide(this.label.content);
            }
        }
        return this;
    },

    /**
     * Make the element visible.
     */
    showElement: function () {
        this.visProp.visible = true;
        this.board.renderer.show(this);

        if (this.label!=null && this.hasLabel && this.label.hiddenByParent) {
            this.label.hiddenByParent = false;
            if (this.label.content.visProp.visible) {
                this.board.renderer.show(this.label.content);
            }
        }
        return this;
    },

    /**
     * Sets the value of property <tt>property</tt> to <tt>value</tt>.
     * @param {String} property The property's name.
     * @param {%} value The new value
     * @private
     */
    _set: function (property, value) {
            property = property.toLocaleLowerCase();

            // Search for entries in visProp with "color" as part of the property name
            // and containing a RGBA string
            if (this.visProp.hasOwnProperty(property) && property.indexOf('color') >= 0 &&
                JXG.isString(value) && value.length == 9 && value.charAt(0) === '#') {

                value = JXG.rgba2rgbo(value);
                this.visProp[property] = value[0];
                this.visProp[property.replace('color', 'opacity')] = value[1]; // Previously: *=. But then, we can only decrease opacity.
            } else {
                this.visProp[property] = value;
            }
    },

    /**
     * Resolves property shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>.
     * Writes the expanded properties back to the given <tt>properties</tt>.
     * @param {Object} properties
     * @returns {Object} The given parameter with shortcuts expanded.
     */
    resolveShortcuts: function(properties) {
        var key, i;
        
        for (key in JXG.Options.shortcuts) {
            if (JXG.exists(properties[key])) {
                for (i = 0; i < JXG.Options.shortcuts[key].length; i++) {
                    if (!JXG.exists(properties[JXG.Options.shortcuts[key][i]])) {
                        properties[JXG.Options.shortcuts[key][i]] = properties[key];
                    }
                }
            }
        }
        return properties;
    },

    /**
     * Updates the element's label text, strips all html.
     * @param {String} str
     */
    setLabelText: function (str) {
        str = str.replace(/</g, '&lt;').replace(/>/g, '&gt;');

        if (this.label !== null) {
            this.label.content.setText(str);
        }
        
        return this;
    },

    /**
     * Sets an arbitrary number of attributes.
     * @param {Object} attributes An object with attributes.
     * @function
     * @example
     * // Set property directly on creation of an element using the attributes object parameter
     * var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 5, 5, 1]};
     * var p = board.create('point', [2, 2], {visible: false});
     *
     * // Now make this point visible and fixed:
     * p.setProperty({
     *     fixed: true,
     *     visible: true
     * });
     */
    setAttribute: JXG.shortcut(JXG.GeometryElement.prototype, 'setProperty'),

    /**
     * Deprecated alias for {@link JXG.GeometryElement#setAttribute}.
     * @deprecated Use {@link JXG.GeometryElement#setAttribute}.
     */
    setProperty: function () {
        var i, key, value, arg, opacity, pair, properties = {}, oldvalue;

        // normalize the user input
        for (i = 0; i < arguments.length; i++) {
            arg = arguments[i];
            if (JXG.isString(arg)) {
                // pairRaw is string of the form 'key:value'
                pair = arg.split(':');
                properties[JXG.trim(pair[0])] = JXG.trim(pair[1]);
            } else if (!JXG.isArray(arg)) {
                // pairRaw consists of objects of the form {key1:value1,key2:value2,...}
                JXG.extend(properties, arg);
            } else {
                // pairRaw consists of array [key,value]
                properties[arg[0]] = arg[1];
            }
        }

        // handle shortcuts
        properties = this.resolveShortcuts(properties);
        
        for (i in properties) {
            key = i.replace(/\s+/g, '').toLowerCase();
            value = properties[i];
            oldvalue = this.visProp[key];
            
            switch(key) {
                case 'name':
                    delete this.board.elementsByName[this.name];
                    this.name = value;
                    this.board.elementsByName[this.name] = this;
                    break;
                case 'needsregularupdate':
                    this.needsRegularUpdate = !(value == 'false' || value == false);
                    this.board.renderer.setBuffering(this, this.needsRegularUpdate ? 'auto' : 'static');
                    break;
                case 'labelcolor':
                    value = JXG.rgba2rgbo(value); 
                    opacity = value[1];
                    value = value[0];
                    if (opacity == 0) {
                        if (this.label!=null && this.hasLabel) {
                            this.label.content.hideElement();
                        }
                    }
                    if (this.label!=null && this.hasLabel) {
                        this.label.color = value;
                        this.board.renderer.setObjectStrokeColor(this.label.content, value, opacity);
                    }
                    if (this.type == JXG.OBJECT_TYPE_TEXT) {
                        this.visProp.strokecolor = value;
                        this.visProp.strokeopacity = opacity;
                        this.board.renderer.setObjectStrokeColor(this, this.visProp.strokecolor, this.visProp.strokeopacity);
                    }
                    break;
                case 'infoboxtext':
                    // TODO: what about functions? numbers? maybe text elements?
                    if (typeof(value) == 'string') {
                        this.infoboxText = value;
                    } else {
                        this.infoboxText = false;
                    }
                    break;
                case 'visible':
                    if (value == 'false' || value == false) {
                        this.visProp.visible = false;
                        this.hideElement();
                    } else if (value == 'true' || value == true) {
                        this.visProp.visible = true;
                        this.showElement();
                    }
                    break;
                case 'face':
                    if (this.elementClass == JXG.OBJECT_CLASS_POINT) {
                        this.visProp.face = value;
                        this.board.renderer.changePointStyle(this);
                    }
                    break;
                case 'trace':
                    if (value == 'false' || value == false) {
                        this.clearTrace();
                        this.visProp.trace = false;
                    } else {
                        this.visProp.trace = true;
                    }
                    break;
                case 'gradient':
                    this.visProp.gradient = value;
                    this.board.renderer.setGradient(this);
                    break;
                case 'gradientsecondcolor':
                    value = JXG.rgba2rgbo(value);
                    this.visProp.gradientsecondcolor = value[0];
                    this.visProp.gradientsecondopacity = value[1];
                    this.board.renderer.updateGradient(this);
                    break;
                case 'gradientsecondopacity':
                    this.visProp.gradientsecondopacity = value;
                    this.board.renderer.updateGradient(this);
                    break;
                case 'withlabel':
                    this.visProp.withlabel = value;
                    if (!value) {
                        if (this.label && this.label.content && this.hasLabel) {
                            this.label.content.hideElement();
                        }
                    } else {
                        if (this.label && this.label.content) {
                            if (this.visProp.visible) {
                                this.label.content.showElement();
                            }
                        } else {
                            this.createLabel();
                            if (!this.visProp.visible) {
                                this.label.content.hideElement();
                            }
                        }
                    }
                    this.hasLabel = value;
                    break;
                case 'rotate':
                    if ((this.type===JXG.OBJECT_TYPE_TEXT && this.visProp.display=='internal')
                        || this.type===JXG.OBJECT_TYPE_IMAGE) {
                        this.addRotation(value);
                    }
                    break;
                case 'ticksdistance':
                    if (this.type === JXG.OBJECT_TYPE_TICKS && typeof value === 'number') {
                        this.ticksFunction = (function (_value) { return function (i) {
                                return _value;
                            };
                        })(value);
                    }
                    break;
                default:
                    if (JXG.exists(this.visProp[key]) && (!JXG.Validator[key] || (JXG.Validator[key] && JXG.Validator[key](value)) || (JXG.Validator[key] && JXG.isFunction(value) && JXG.Validator[key](value())))) {
                        value = value.toLowerCase && value.toLowerCase() === 'false' ? false : value;
                        this._set(key, value);
                    }
                    break;
            }
            this.triggerEventHandlers('attribute:' + key, oldvalue);
        }
        
        this.triggerEventHandlers('attribute', properties);

        if (!this.visProp.needsregularupdate) {
            this.board.fullUpdate();
        } else {
            this.board.update(this);
        }
        
        return this;
    },

    /**
     * Get the value of the property <tt>key</tt>.
     * @param {String} key The name of the property you are looking for
     * @returns The value of the property
     */
    getAttribute: JXG.shortcut(JXG.GeometryElement.prototype, 'getProperty'),

    /**
     * Deprecated alias for {@link JXG.GeometryElement#getAttribute}.
     * @deprecated Use {@link JXG.GeometryElement#getAttribute}.
     */
    getProperty: function (key) {
        var result;
        key = key.toLowerCase();

        switch (key) {
            case 'needsregularupdate':
                result = this.needsRegularUpdate;
                break;
            case 'labelcolor':
                result = this.label.color;
                break;
            case 'infoboxtext':
                result = this.infoboxText;
                break;
            case 'withlabel':
                result = this.hasLabel;
                break;
            default:
                result = this.visProp[key];
                break;
        }

        return result;
    },

    /**
     * Set the dash style of an object. See {@link #dash} for a list of available dash styles.
     * You should use {@link #setProperty} instead of this method.
     * @param {number} dash Indicates the new dash style
     * @private
     */
    setDash: function (dash) {
        this.setProperty({dash: dash});
        return this;
    },

    /**
     * Notify all child elements for updates.
     * @private
     */
    prepareUpdate: function () {
        this.needsUpdate = true;
        return this;
    },

    /**
     * Removes the element from the construction.  This only removes the SVG or VML node of the element and its label (if available) from
     * the renderer, to remove the element completely you should use {@link JXG.Board#removeObject}.
     */
    remove: function () {
        this.board.renderer.remove(this.board.renderer.getElementById(this.id));

        if (this.hasLabel) {
            this.board.renderer.remove(this.board.renderer.getElementById(this.label.content.id));
        }
        return this;
    },

    /**
     * Returns the coords object where a text that is bound to the element shall be drawn.
     * Differs in some cases from the values that getLabelAnchor returns.
     * @returns {JXG.Coords} JXG.Coords Place where the text shall be drawn.
     * @see JXG.GeometryElement#getLabelAnchor
     */
    getTextAnchor: function () {
        return new JXG.Coords(JXG.COORDS_BY_USER, [0,0], this.board);
    },

    /**
     * Returns the coords object where the label of the element shall be drawn.
     * Differs in some cases from the values that getTextAnchor returns.
     * @returns {JXG.Coords} JXG.Coords Place where the text shall be drawn.
     * @see JXG.GeometryElement#getTextAnchor
     */
    getLabelAnchor: function () {
        return new JXG.Coords(JXG.COORDS_BY_USER, [0,0], this.board);
    },

    /**
     * TODO
     * Was hat das hier verloren? "Straights" gibts doch nur fuer Lines oder?
     * Sollte das dann nicht nur in Line.js zu finden sein? --michael
     * @description none yet
     * @private
     */
    setStraight: function (x,y) {
        return this;
    },

    /**
     * Determines whether the arc has arrows at start or end of the arc.
     * @param {bool} firstArrow True if there is an arrow at the start of the arc, false otherwise.
     * @param {bool} lastArrow True if there is an arrow at the end of the arc, false otherwise.
     * Is stored at visProp['firstarrow'] and visProp['lastarrow']
     */
    setArrow: function (firstArrow, lastArrow) {
        this.visProp.firstarrow = firstArrow;
        this.visProp.lastarrow = lastArrow;
        this.prepareUpdate().update();
        return this;
    },

    /**
     * Creates a gradient nodes in the renderer.
     * @see JXG.SVGRenderer#setGradient
     * @private
     */
    createGradient: function() {
        if (this.visProp.gradient === 'linear' || this.visProp.gradient === 'radial' ) {
            this.board.renderer.setGradient(this);
        }
    },
           
    /**
     * Creates a label element for this geometry element.
     * @see #addLabelToElement
     */
    createLabel: function () {
        var attr = {};
        
        attr =  JXG.deepCopy(this.visProp.label, null);
        attr.id = this.id + 'Label';
        attr.isLabel = true;
        attr.visible = this.visProp.visible;
        attr.anchor = this;
        attr.priv = this.visProp.priv;
        
        this.nameHTML = JXG.GeonextParser.replaceSup(JXG.GeonextParser.replaceSub(this.name));
        this.label = {};

        if (this.visProp.withlabel) {
            this.label.relativeCoords = [0, 0];

            this.label.content = JXG.createText(this.board, 
                [this.label.relativeCoords[0], -this.label.relativeCoords[1], this.name], 
                attr);
            this.label.content.needsUpdate = true;
            this.label.content.update();

            this.label.content.dump = false;
            this.label.color = this.label.content.visProp.strokecolor;

            if (!this.visProp.visible) {
                this.label.hiddenByParent = true;
                this.label.content.visProp.visible = false;
            }
            this.hasLabel = true;
        }
        return this;
    },

    /**
     * Highlights the element.
     * @param {Boolean} [force=false] Force the highlighting
     * @returns {JXG.Board}
     */
    highlight: function (force) {
        force = JXG.def(force, false);
        // I know, we have the JXG.Board.highlightedObjects AND JXG.GeometryElement.highlighted and YES we need both.
        // Board.highlightedObjects is for the internal highlighting and GeometryElement.highlighted is for user highlighting
        // initiated by the user, e.g. through custom DOM events. We can't just pick one because this would break user
        // defined highlighting in many ways:
        //  * if overriding the highlight() methods the user had to handle the highlightedObjects stuff, otherwise he'd break
        //    everything (e.g. the pie chart example http://jsxgraph.uni-bayreuth.de/wiki/index.php/Pie_chart (not exactly
        //    user defined but for this type of chart the highlight method was overridden and not adjusted to the changes in here)
        //    where it just kept highlighting until the radius of the pie was far beyond infinity...
        //  * user defined highlighting would get pointless, everytime the user highlights something using .highlight(), it would get
        //    dehighlighted immediately, because highlight puts the element into highlightedObjects and from there it gets dehighlighted
        //    through dehighlightAll.
        if (!this.highlighted || force) { // highlight only if not highlighted
            this.highlighted = true;
            this.board.renderer.highlight(this);
        }
        return this;
    },

    /**
     * Uses the "normal" properties of the element.
     * @returns {JXG.Board}
     */
    noHighlight: function () {
        // see comment in JXG.GeometryElement.highlight()
        if (this.highlighted) { // dehighlight only if not highlighted
            this.highlighted = false;
            this.board.renderer.noHighlight(this);
        }
        return this;
    },

    /**
     * Removes all objects generated by the trace function.
     */
    clearTrace: function () {
        var obj;
        for (obj in this.traces) {
            this.board.renderer.remove(this.traces[obj]);
        }
        this.numTraces = 0;
        return this;
    },

    /**
     * Copy the element to background. This is used for tracing elements.
     * @returns {JXG.GeometryElement} A reference to the element
     */
    cloneToBackground: function () {
        return this;
    },

    /**
     * Dimensions of the smallest rectangle enclosing the element.
     * @returns {Array} The coordinates of the enclosing rectangle in a format like the bounding box in {@link JXG.Board#setBoundingBox}.
     */
    bounds: function () { },

    /**
     * Normalize the element's standard form.
     * @private
     */
    normalize: function () {
        this.stdform = JXG.Math.normalize(this.stdform);
        return this;
    },

    /**
     * EXPERIMENTAL. Generate JSON object code of visProp and other properties.
     * @type string
     * @private
     * @ignore
     * @return JSON string containing element's properties.
     */
    toJSON: function () {
        var json = '{"name":' + this.name;
        json += ', ' + '"id":' + this.id;

        var vis = [];
        for (var key in this.visProp) {
            if (this.visProp[key]!=null) {
                vis.push('"' + key + '":' + this.visProp[key]);
            }
        }
        json += ', "visProp":{'+vis.toString()+'}';
        json +='}';

        return json;
    },

    
    /**
     * Rotate texts or images by a given degree. Works only for texts where JXG.Text#display equal to "internal".
     * @param {number} angle The degree of the rotation (90 means vertical text).
     * @see JXG.GeometryElement#rotate
     */
    addRotation: function(angle) {
        var tOffInv, tOff, tS, tSInv, tRot, that = this;
        
        if (((this.type===JXG.OBJECT_TYPE_TEXT && this.visProp.display==='internal')
              || this.type===JXG.OBJECT_TYPE_IMAGE
             )
            && angle!=0) {
            var tOffInv, tOff, tS, tSInv, tRot, that = this;

            tOffInv = this.board.create('transform', [function(){return -that.X()}, function(){return -that.Y()}], {type:'translate'});
            tOff = this.board.create('transform', [function(){return that.X()}, function(){return that.Y()}], {type:'translate'});
       
            tS = this.board.create('transform', [
                    function() { return that.board.unitX/that.board.unitY; },                
                    function() { return 1; }
                ], {type:'scale'});
            tSInv = this.board.create('transform', [
                    function() { return that.board.unitY/that.board.unitX; },                
                    function() { return 1; }
                ], {type:'scale'});
            tRot = this.board.create('transform', [angle*Math.PI/180.0], {type:'rotate'});
        
            tOffInv.bindTo(this);                                                   
            tS.bindTo(this);
            tRot.bindTo(this);
            tSInv.bindTo(this);
            tOff.bindTo(this);
        }
        
        return this;
    },
    
    /**
     * Set the highlightStrokeColor of an element
     * @param {String} sColor String which determines the stroke color of an object when its highlighted.
     * @see JXG.GeometryElement#highlightStrokeColor
     */
    highlightStrokeColor: function (sColor) {
        this.setProperty({highlightStrokeColor:sColor});
        return this;
    },

    /**
     * Set the strokeColor of an element
     * @param {String} sColor String which determines the stroke color of an object.
     * @see JXG.GeometryElement#strokeColor
     */
    strokeColor: function (sColor) {
        this.setProperty({strokeColor:sColor});
        return this;
    },

    /**
     * Set the strokeWidth of an element
     * @param {Number} width Integer which determines the stroke width of an outline.
     * @see JXG.GeometryElement#strokeWidth
     */
    strokeWidth: function (width) {
        this.setProperty({strokeWidth:width});
        return this;
    },


    /**
     * Set the fillColor of an element
     * @param {String} fColor String which determines the fill color of an object.
     * @see JXG.GeometryElement#fillColor
     */
    fillColor: function (fColor) {
        this.setProperty({fillColor:fColor});
        return this;
    },

    /**
     * Set the highlightFillColor of an element
     * @param {String} fColor String which determines the fill color of an object when its highlighted.
     * @see JXG.GeometryElement#highlightFillColor
     */
    highlightFillColor: function (fColor) {
        this.setProperty({highlightFillColor:fColor});
        return this;
    },

    /**
     * Set the labelColor of an element
     * @param {String} lColor String which determines the text color of an object's label.
     * @see JXG.GeometryElement#labelColor
     */
    labelColor: function (lColor) {
        this.setProperty({labelColor:lColor});
        return this;
    },

    /**
     * Set the dash type of an element
     * @param {Number} d Integer which determines the way of dashing an element's outline.
     * @see JXG.GeometryElement#dash
     */
    dash: function (d) {
        this.setProperty({dash:d});
        return this;
    },

    /**
     * Set the visibility of an element
     * @param {Boolean} v Boolean which determines whether the element is drawn.
     * @see JXG.GeometryElement#visible
     */
    visible: function (v) {
        this.setProperty({visible:v});
        return this;
    },

    /**
     * Set the shadow of an element
     * @param {Boolean} s Boolean which determines whether the element has a shadow or not.
     * @see JXG.GeometryElement#shadow
     */
    shadow: function (s) {
        this.setProperty({shadow:s});
        return this;
    },

    /**
     * The type of the element as used in {@link JXG.Board#create}.
     * @returns {String}
     */
    getType: function () {
        return this.elType;
    },

    /**
     * List of the element ids resp. values used as parents in {@link JXG.Board#create}.
     * @returns {Array}
     */
    getParents: function () {
        return this.parents;
    },

    /**
     * Snaps the element to the grid. Only works for points, lines and circles. Points will snap to the grid
     * as defined in their properties {@link JXG.Point#snapSizeX} and {@link JXG.Point#snapSizeY}. Lines and circles
     * will snap their parent points to the grid, if they have {@link JXG.Point#snapToGrid} set to true.
     * @returns {JXG.GeometryElement} Reference to the element.
     */
    snapToGrid: function () {
        return this;    },

    /**
     * Retrieve a copy of the current visProp.
     * @returns {Object}
     */
    getAttributes: function () {
        var attributes = JXG.deepCopy(this.visProp),
            cleanThis = ['attractors', 'attractordistance', 'snatchdistance', 'traceattributes', 'frozen',
                'shadow', 'gradientangle', 'gradientsecondopacity', 'gradientpositionx', 'gradientpositiony',
                'needsregularupdate', 'zoom', 'layer', 'offset'],
            i;

        attributes.id = this.id;
        attributes.name = this.name;

        for (i = 0; i < cleanThis.length; i++) {
            delete attributes[cleanThis[i]];
        }

        return attributes;
    },

    /**
     * Checks whether (x,y) is near the element.
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @returns {Boolean} True if (x,y) is near the element, False otherwise.
     */
    hasPoint: function (x, y) {
        return false;
    },

    /**
     * Alias of {@link JXG.GeometryElement#on}.
     */
    addEvent: JXG.shortcut(JXG.GeometryElement.prototype, 'on'),

    /**
     * Alias of {@link JXG.GeometryElement#off}.
     */
    removeEvent: JXG.shortcut(JXG.GeometryElement.prototype, 'off'),
    
    /* **************************
     *     EVENT DEFINITION
     * for documentation purposes
     * ************************** */

    //region Event handler documentation
    /**
     * @event
     * @description This event is fired whenever the user is hovering over an element.
     * @name JXG.GeometryElement#over
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user puts the mouse over an element.
     * @name JXG.GeometryElement#mouseover
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user is leaving an element.
     * @name JXG.GeometryElement#out
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user puts the mouse away from an element.
     * @name JXG.GeometryElement#mouseout
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user is moving over an element.
     * @name JXG.GeometryElement#move
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user is moving the mouse over an element.
     * @name JXG.GeometryElement#mousemove
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user drags an element.
     * @name JXG.GeometryElement#drag
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user drags the element with a mouse.
     * @name JXG.GeometryElement#mousedrag
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description This event is fired whenever the user drags the element on a touch device.
     * @name JXG.GeometryElement#touchdrag
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description Whenever the user starts to touch or click an element.
     * @name JXG.GeometryElement#down
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description Whenever the user starts to click an element.
     * @name JXG.GeometryElement#mousedown
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description Whenever the user starts to touch an element.
     * @name JXG.GeometryElement#touchdown
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description Whenever the user stops to touch or click an element.
     * @name JXG.GeometryElement#up
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description Whenever the user releases the mousebutton over an element.
     * @name JXG.GeometryElement#mouseup
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) { },

    /**
     * @event
     * @description Whenever the user stops touching an element.
     * @name JXG.GeometryElement#touchup
     * @param {Event} e The browser's event object.
     */
    __evt__: function (e) {},

    /**
     * @event
     * @description Notify everytime an attribute is changed.
     * @name JXG.GeometryElement#attribute
     * @param {Object} o A list of changed attributes and their new value.
     */
    __evt__: function (o) {},

    /**
     * @event
     * @description This is a generic event handler. It exists for every possible attribute that can be set for
     * any element, e.g. if you want to be notified everytime an element's strokecolor is changed, is the event
     * <tt>attribute:strokecolor</tt>.
     * @name JXG.GeometryElement#attribute:&lt;attribute&gt;
     * @param {%} val The old value.
     */
    __evt__: function (val) {},

    /**
     * @ignore
     */
    __evt__: function () {}
    //endregion

});


/* 
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/** 
 * @fileoverview In this file the Coords object is defined, a class to manage all
 * properties and methods coordinates usually have.
 * @author graphjs
 * @version 0.1
 */

JXG.COORDS_BY_USER = 0x0001;
JXG.COORDS_BY_SCREEN = 0x0002;

/**
 * Constructs a new Coordinates object.
 * @class This is the Coordinates class.  
 * All members a coordinate has to provide
 * are defined here.
 * @param {int} method The type of coordinates given by the user. Accepted values are <b>COORDS_BY_SCREEN</b> and <b>COORDS_BY_USER</b>.
 * @param {Array} coordinates An array of affine coordinates.
 * @param {JXG.AbstractRenderer} renderer A reference to a Renderer.
 * @borrows JXG.EventEmitter#on as this.on
 * @borrows JXG.EventEmitter#off as this.off
 * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers
 * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers
 * @constructor
 */
JXG.Coords = function (method, coordinates, board) {
    /**
     * Stores the board the object is used on.
     * @type JXG.Board
     */
    this.board = board;
    
    /**
     * Stores coordinates for user view as homogeneous coordinates.
     * @type Array
     */
    this.usrCoords = [];
    /**
     * Stores coordinates for screen view as homogeneous coordinates.
     * @type Array
     */
    this.scrCoords = [];
    
    JXG.EventEmitter.eventify(this);
    this.setCoordinates(method, coordinates);
};

JXG.extend(JXG.Coords.prototype, /** @lends JXG.Coords.prototype */ {
    /**
     * Normalize homogeneous coordinates
     * @private
     */
    normalizeUsrCoords: function () {
        var eps = JXG.Math.eps;
        if (Math.abs(this.usrCoords[0]) > eps) {
            this.usrCoords[1] /= this.usrCoords[0];
            this.usrCoords[2] /= this.usrCoords[0];
            this.usrCoords[0] = 1.0;
        }
    },

    /**
     * Compute screen coordinates out of given user coordinates.
     * @private
     */
    usr2screen: function (doRound) {
        var mround = Math.round,  // Is faster on IE, maybe slower with JIT compilers
            b = this.board,
            uc = this.usrCoords,
            oc = b.origin.scrCoords;

        if (doRound === null || doRound) {
            this.scrCoords[0] = mround(uc[0]);
            this.scrCoords[1] = mround(uc[0]*oc[1] + uc[1]*b.unitX);
            this.scrCoords[2] = mround(uc[0]*oc[2] - uc[2]*b.unitY);
        } else {
            this.scrCoords[0] = uc[0];
            this.scrCoords[1] = uc[0]*oc[1] + uc[1]*b.unitX;
            this.scrCoords[2] = uc[0]*oc[2] - uc[2]*b.unitY;
        }
    },

    /**
     * Compute user coordinates out of given screen coordinates.
     * @private
     */
    screen2usr: function () {
        var o = this.board.origin.scrCoords,
            sc = this.scrCoords,
            b = this.board;
        this.usrCoords[0] =  1.0;
        this.usrCoords[1] = (sc[1] - o[1])/b.unitX;
        this.usrCoords[2] = (o[2] - sc[2])/b.unitY;
    },

    /**
     * Calculate distance of one point to another.
     * @param {Number} coord_type The type of coordinates used here. Possible values are <b>JXG.COORDS_BY_USER</b> and <b>JXG.COORDS_BY_SCREEN</b>.
     * @param {JXG.Coords} coordinates The Coords object to which the distance is calculated.
     * @returns {Number} The distance
     */
    distance: function (coord_type, coordinates) {
        var sum = 0,
            c,
            ucr = this.usrCoords,
            scr = this.scrCoords,
            f;

        if (coord_type === JXG.COORDS_BY_USER) {
            c = coordinates.usrCoords;
            f = ucr[0]-c[0];
            sum = f*f;
            if (sum>JXG.Math.eps) {
                return Number.POSITIVE_INFINITY;
            }
            f = ucr[1]-c[1];
            sum += f*f;
            f = ucr[2]-c[2];
            sum += f*f;
        } else {
            c = coordinates.scrCoords;
            //f = scr[0]-c[0];
            //sum = f*f;
            f = scr[1]-c[1];
            sum += f*f;
            f = scr[2]-c[2];
            sum += f*f;
        }

        return Math.sqrt(sum);
    },

    /**
     * Set coordinates by either user coordinates or screen coordinates and recalculate the other one.
     * @param {Number} coord_type The type of coordinates used here. Possible values are <b>COORDS_BY_USER</b> and <b>COORDS_BY_SCREEN</b>.
     * @param {Array} coordinates An array of affine coordinates the Coords object is set to.
     * @param {Boolean} [doRound=true] flag If true or null round the coordinates in usr2screen. This is used in smooth curve plotting.
     * The IE needs rounded coordinates. Id doRound==false we have to round in updatePathString.
     * @returns {JXG.Coords} Reference to the coords object.
     */
    setCoordinates: function (coord_type, coordinates, doRound) {
        var uc = this.usrCoords,
            sc = this.scrCoords,
            ou = this.usrCoords.slice(0), os = this.scrCoords.slice(0);

        if (coord_type === JXG.COORDS_BY_USER) {
            if (coordinates.length === 2) { // Euclidean coordinates
                uc[0] = 1.0;
                uc[1] = coordinates[0];
                uc[2] = coordinates[1];
            } else { // Homogeneous coordinates (normalized)
                uc[0] = coordinates[0];
                uc[1] = coordinates[1];
                uc[2] = coordinates[2];
                this.normalizeUsrCoords();
            }
            this.usr2screen(doRound);
        } else {
            sc[1] = coordinates[0];
            sc[2] = coordinates[1];
            this.screen2usr();
        }
        
        this.triggerEventHandlers('update', ou, os);

        return this;
    },

    /**
     * Triggered whenever the coordinates change.
     * @name JXG.Coords#update
     * @param {Array} ou Old user coordinates
     * @param {Array} os Old screen coordinates
     * @event
     */
    __evt__: function (ou, os) { },

    /**
     * @ignore
     */
    __evt__: function () {}
});


/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview The geometry object Point is defined in this file. Point stores all
 * style and functional properties that are required to draw and move a point on
 * a board.
 */


/**
 * A point is the basic geometric element. Based on points lines and circles can be constructed which can be intersected
 * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for
 * all kind of points like free points, gliders, and intersection points.
 * @class Creates a new point object. Do not use this constructor to create a point. Use {@link JXG.Board#create} with
 * type {@link Point}, {@link Glider}, or {@link Intersection} instead.  
 * @augments JXG.GeometryElement
 * @param {string|JXG.Board} board The board the new point is drawn on.
 * @param {Array} coordinates An array with the affine user coordinates of the point.
 * @param {Object} attributes An object containing visual properties like in {@link JXG.Options#point} and
 * {@link JXG.Options#elements}, and optional a name and a id.
 * @see JXG.Board#generateName
 * @see JXG.Board#addPoint
 */
JXG.Point = function (board, coordinates, attributes) {
    this.constructor(board, attributes, JXG.OBJECT_TYPE_POINT, JXG.OBJECT_CLASS_POINT);
    
    if (coordinates==null) {
        coordinates=[0,0];
    }
    /**
     * Coordinates of the point.
     * @type JXG.Coords
     * @private
     */
    this.coords = new JXG.Coords(JXG.COORDS_BY_USER, coordinates, this.board);
    this.initialCoords = new JXG.Coords(JXG.COORDS_BY_USER, coordinates, this.board);
        
    /**
     * Relative position on a line if point is a glider on a line.
     * @type Number
     * @private
     */
    this.position = null;

    /**
     * Determines whether the point slides on a polygon if point is a glider.
     * @type boolean
     * @default false
     * @private
     */
    this.onPolygon = false;
        
    /**
     * When used as a glider this member stores the object, where to glide on. To set the object to glide on use the method
     * {@link JXG.Point#makeGlider} and DO NOT set this property directly as it will break the dependency tree.
     * TODO: Requires renaming to glideObject
     * @type JXG.GeometryElement
     * @name Glider#slideObject
     */
    this.slideObject = null;

    this.Xjc = null;
    this.Yjc = null;

    // documented in GeometryElement
    this.methodMap = JXG.deepCopy(this.methodMap, {
        move: 'moveTo',
        glide: 'makeGlider',
        X: 'X',
        Y: 'Y',
        free: 'free',
        setPosition: 'setGliderPosition'
    });

    /**
     * Stores the groups of this point in an array of Group.
     * @type array
     * @see JXG.Group
     * @private
     */
    this.group = [];

    this.elType = 'point';

    /* Register point at board. */
    this.id = this.board.setId(this, 'P');
    this.board.renderer.drawPoint(this);
    this.board.finalizeAdding(this);

    this.createLabel();
};

/**
 * Inherits here from {@link JXG.GeometryElement}.
 */
JXG.Point.prototype = new JXG.GeometryElement();


JXG.extend(JXG.Point.prototype, /** @lends JXG.Point.prototype */ {
    /**
     * Checks whether (x,y) is near the point.
     * @param {int} x Coordinate in x direction, screen coordinates.
     * @param {int} y Coordinate in y direction, screen coordinates.
     * @type boolean
     * @return True if (x,y) is near the point, False otherwise.
     * @private
     */
    hasPoint: function (x,y) {
        var coordsScr = this.coords.scrCoords, r;
        r = parseFloat(this.visProp.size) + parseFloat(this.visProp.strokewidth)*0.5;
        if(r < this.board.options.precision.hasPoint) {
            r = this.board.options.precision.hasPoint;
        }

        return ((Math.abs(coordsScr[1]-x) < r+2) && (Math.abs(coordsScr[2]-y)) < r+2);
    },

    /**
    * Dummy function for unconstrained points or gliders.
    * @private
    */
    updateConstraint: function() { return this; },

    /**
     * Updates the position of the point.
     */
    update: function (fromParent) {
        if (!this.needsUpdate) { return this; }

        if(typeof fromParent == 'undefined') {
            fromParent = false;
        }
            
        /*
         * We need to calculate the new coordinates no matter of the points visibility because
         * a child could be visible and depend on the coordinates of the point (e.g. perpendicular).
         * 
         * Check if point is a glider and calculate new coords in dependency of this.slideObject.
         * This function is called with fromParent==true for example if
         * the defining elements of the line or circle have been changed.
         */
        if(this.type == JXG.OBJECT_TYPE_GLIDER) {
            if (fromParent) {
                this.updateGliderFromParent();
            } else {
                this.updateGlider();
            }
        }
                
        /**
        * If point is a calculated point, call updateConstraint() to calculate new coords. 
        * The second test is for dynamic axes.
        */
        if (this.type == JXG.OBJECT_TYPE_CAS || this.type == JXG.OBJECT_TYPE_AXISPOINT) {
            this.updateConstraint();
        }

        this.updateTransform();
                
        if(this.visProp.trace) {
            this.cloneToBackground(true);
        }

        return this;
    },

    /**
    * Update of glider in case of dragging the glider or setting the postion of the glider.
    * The relative position of the glider has to be updated.
    * If the second point is an ideal point, then -1 < this.position < 1,
    * this.position==+/-1 equals point2, this.position==0 equals point1
    * 
    * If the first point is an ideal point, then 0 < this.position < 2
    * this.position==0  or 2 equals point1, this.position==1 equals point2
    * 
    * @private
    */
    updateGlider: function() {
        var i, p1c, p2c, d, v, poly, cc, pos, sgn,
            slide = this.slideObject, alpha, beta, angle,
            cp, c, invMat;

        if (slide.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
            this.coords  = JXG.Math.Geometry.projectPointToCircle(this, slide, this.board);
            this.position = JXG.Math.Geometry.rad([slide.center.X()+1.0,slide.center.Y()],slide.center,this);
        } else if (slide.elementClass == JXG.OBJECT_CLASS_LINE) {

            /** 
             * onPolygon==true: the point is a slider on a seg,ent and this segment is one of the 
             * "borders" of a polygon.
             * This is a GEONExT feature.
             **/
            if (this.onPolygon) {
                p1c = slide.point1.coords.usrCoords;
                p2c = slide.point2.coords.usrCoords;
                i = 1;
                d = p2c[i] - p1c[i];
                if (Math.abs(d)<JXG.Math.eps) { 
                    i = 2; 
                    d = p2c[i] - p1c[i];
                }
                cc = JXG.Math.Geometry.projectPointToLine(this, slide, this.board);
                pos = (cc.usrCoords[i] - p1c[i]) / d;
                poly = slide.parentPolygon;

                if (pos<0.0) {
                    for (i=0; i<poly.borders.length; i++) {
                        if (slide == poly.borders[i]) {
                            slide = poly.borders[(i - 1 + poly.borders.length) % poly.borders.length];
                            break;
                        }
                    }
                } else if (pos>1.0) {
                    for (i=0; i<poly.borders.length; i++) {
                        if(slide == poly.borders[i]) {
                            slide = poly.borders[(i + 1 + poly.borders.length) % poly.borders.length];
                            break;                        
                        }
                    }
                }
            }

            p1c = slide.point1.coords;
            p2c = slide.point2.coords;
            // Distance between the two defining points
            d = p1c.distance(JXG.COORDS_BY_USER, p2c);
            p1c = p1c.usrCoords.slice(0);
            p2c = p2c.usrCoords.slice(0);
                        
            if (d<JXG.Math.eps) {                                        // The defining points are identical
                this.coords.setCoordinates(JXG.COORDS_BY_USER, p1c);
                this.position = 0.0;
            } else {
                this.coords = JXG.Math.Geometry.projectPointToLine(this, slide, this.board);
                if (Math.abs(p2c[0])<JXG.Math.eps) {                 // The second point is an ideal point
                    i = 1;
                    d = p2c[i];
                    if (Math.abs(d)<JXG.Math.eps) { 
                        i = 2; 
                        d = p2c[i];
                    }
                    d = (this.coords.usrCoords[i] - p1c[i]) / d;
                    sgn = (d>=0) ? 1 : -1;
                    d = Math.abs(d);
                    this.position = sgn * d/(d+1);
                } else if (Math.abs(p1c[0])<JXG.Math.eps) {          // The first point is an ideal point
                    i = 1;
                    d = p1c[i];
                    if (Math.abs(d)<JXG.Math.eps) { 
                        i = 2; 
                        d = p1c[i];
                    }
                    d = (this.coords.usrCoords[i] - p2c[i]) / d;
                    if (d<0.0) {
                        this.position = (1 - 2.0*d) / (1.0 - d); // 1.0 - d/(1-d);
                    } else {
                        this.position = 1/(d+1);
                    }
                } else {
                    i = 1;
                    d = p2c[i] - p1c[i];
                    if (Math.abs(d)<JXG.Math.eps) { 
                        i = 2; 
                        d = p2c[i] - p1c[i];
                    }
                    this.position = (this.coords.usrCoords[i] - p1c[i]) / d;
                }
            }        
                                
            // Snap the glider point of the slider into its appropiate position
            // First, recalculate the new value of this.position
            // Second, call update(fromParent==true) to make the positioning snappier.
            if (this.visProp.snapwidth>0.0 && Math.abs(this._smax-this._smin)>=JXG.Math.eps) {
                if (this.position<0.0) this.position = 0.0;
                if (this.position>1.0) this.position = 1.0;
                                        
                v = this.position*(this._smax-this._smin)+this._smin;
                v = Math.round(v/this.visProp.snapwidth)*this.visProp.snapwidth;
                this.position = (v-this._smin)/(this._smax-this._smin);
                this.update(true);
            }

            p1c = slide.point1.coords.usrCoords;
            if (!slide.visProp.straightfirst && Math.abs(p1c[0])>JXG.Math.eps && this.position<0) {
                this.coords.setCoordinates(JXG.COORDS_BY_USER, p1c);
                this.position = 0;
            }
            p2c = slide.point2.coords.usrCoords;
            if (!slide.visProp.straightlast && Math.abs(p2c[0])>JXG.Math.eps && this.position>1) {
                this.coords.setCoordinates(JXG.COORDS_BY_USER, p2c);
                this.position = 1;
            }
        

        } else if (slide.type == JXG.OBJECT_TYPE_TURTLE) {
            this.updateConstraint(); // In case, the point is a constrained glider.
            this.coords  = JXG.Math.Geometry.projectPointToTurtle(this, slide, this.board);  // side-effect: this.position is overwritten
        } else if(slide.elementClass == JXG.OBJECT_CLASS_CURVE) {
                        
            if ((slide.type == JXG.OBJECT_TYPE_ARC 
                || slide.type == JXG.OBJECT_TYPE_SECTOR)) {
                                
                this.coords  = JXG.Math.Geometry.projectPointToCircle(this, slide, this.board);

                angle = JXG.Math.Geometry.rad(slide.radiuspoint, slide.center, this);
                alpha = 0.0;
                beta = JXG.Math.Geometry.rad(slide.radiuspoint, slide.center, slide.anglepoint);
                this.position = angle;
                                

                if ((slide.visProp.type=='minor' && beta>Math.PI)
                    || (slide.visProp.type=='major' && beta<Math.PI)) { 
                    alpha = beta; 
                    beta = 2*Math.PI;
                }      
                                                
                if (angle<alpha || angle>beta) {         // Correct the position if we are outside of the sector/arc
                    this.position = beta;
                    if ((angle<alpha && angle>alpha*0.5) || (angle>beta && angle>beta*0.5 + Math.PI)) {
                        this.position = alpha;
                    }
                    this.updateGliderFromParent();
                } 

            } else {
                this.updateConstraint(); // In case, the point is a constrained glider.

                if (slide.transformations.length>0) {
                    slide.updateTransformMatrix();
                    invMat = JXG.Math.inverse(slide.transformMat);
                    c = JXG.Math.matVecMult(invMat, this.coords.usrCoords);
                                        
                    cp = (new JXG.Coords(JXG.COORDS_BY_USER, c, this.board)).usrCoords;
                    c = JXG.Math.Geometry.projectCoordsToCurve(cp[1], cp[2], this.position||0.0, slide, this.board);
                    this.position = c[1];      // side effect !
                    this.coords = c[0];
                } else {
                    this.coords  = JXG.Math.Geometry.projectPointToCurve(this, slide, this.board);  
                    // side-effect: this.position is overwritten
                }
            }
                        
        } else if(slide.elementClass == JXG.OBJECT_CLASS_POINT) {
            this.coords  = JXG.Math.Geometry.projectPointToPoint(this, slide, this.board);
        }
    },

    /**
    * Update of a glider in case a parent element has been updated. That means the 
    * relative position of the glider stays the same.
    * @private
    */
    updateGliderFromParent: function() {
        var p1c, p2c, r, lbda, c,
            slide = this.slideObject, alpha;

        if(slide.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
            r = slide.Radius();
            this.coords.setCoordinates(JXG.COORDS_BY_USER, [
                    slide.center.X() + r*Math.cos(this.position),
                    slide.center.Y() + r*Math.sin(this.position)
                ]);
        } else if(slide.elementClass == JXG.OBJECT_CLASS_LINE) {
            p1c = slide.point1.coords.usrCoords;
            p2c = slide.point2.coords.usrCoords;
            if (Math.abs(p2c[0])<JXG.Math.eps) {                        // The second point is an ideal point
                lbda = Math.min(Math.abs(this.position), 1.0-JXG.Math.eps);
                lbda /= (1.0-lbda);
                if (this.position < 0) {
                    lbda *= -1.0;
                }
                this.coords.setCoordinates(JXG.COORDS_BY_USER, [
                    p1c[0] + lbda*p2c[0],
                    p1c[1] + lbda*p2c[1],
                    p1c[2] + lbda*p2c[2]
                ]);
            } else if (Math.abs(p1c[0])<JXG.Math.eps) {                 // The first point is an ideal point
                lbda = Math.max(this.position, JXG.Math.eps);
                lbda = Math.min(lbda, 2.0-JXG.Math.eps);
                if (lbda > 1.0) {
                    lbda = (lbda-1)/(lbda-2);
                } else {
                    lbda = (1.0-lbda)/lbda;
                }
                this.coords.setCoordinates(JXG.COORDS_BY_USER, [
                    p2c[0] + lbda*p1c[0],
                    p2c[1] + lbda*p1c[1],
                    p2c[2] + lbda*p1c[2]
                ]);
            } else {
                lbda = this.position;
                this.coords.setCoordinates(JXG.COORDS_BY_USER, [
                    p1c[0] + lbda*(p2c[0]-p1c[0]),
                    p1c[1] + lbda*(p2c[1]-p1c[1]),
                    p1c[2] + lbda*(p2c[2]-p1c[2])
                ]);
            }
        } else if(slide.type == JXG.OBJECT_TYPE_TURTLE) {
            this.coords.setCoordinates(JXG.COORDS_BY_USER, [slide.Z(this.position), slide.X(this.position), slide.Y(this.position)]);
            this.updateConstraint(); // In case, the point is a constrained glider.
            this.coords  = JXG.Math.Geometry.projectPointToTurtle(this, slide, this.board);  // side-effect: this.position is overwritten
        } else if(slide.elementClass == JXG.OBJECT_CLASS_CURVE) {
            this.coords.setCoordinates(JXG.COORDS_BY_USER, [slide.Z(this.position), slide.X(this.position), slide.Y(this.position)]);
                        
            if (slide.type == JXG.OBJECT_TYPE_ARC || slide.type == JXG.OBJECT_TYPE_SECTOR) {
                alpha = JXG.Math.Geometry.rad([slide.center.X()+1, slide.center.Y()], slide.center, slide.radiuspoint);
                r = slide.Radius();
                this.coords.setCoordinates(JXG.COORDS_BY_USER, [
                        slide.center.X() + r*Math.cos(this.position+alpha),
                        slide.center.Y() + r*Math.sin(this.position+alpha)
                    ]);
            } else {
                this.updateConstraint(); // In case, the point is a constrained glider.
                this.coords  = JXG.Math.Geometry.projectPointToCurve(this, slide, this.board);  
                // side-effect: this.position is overwritten
            }
                        
        } else if(slide.elementClass == JXG.OBJECT_CLASS_POINT) {
            this.coords  = JXG.Math.Geometry.projectPointToPoint(this, slide, this.board);
        }
    },

    /**
     * Calls the renderer to update the drawing.
     * @private
     */
    updateRenderer: function () {
        if (!this.needsUpdate) { return this; }

        /* Call the renderer only if point is visible. */
        if(this.visProp.visible && this.visProp.size > 0) {
            var wasReal = this.isReal;
            this.isReal = (!isNaN(this.coords.usrCoords[1] + this.coords.usrCoords[2]));
            this.isReal = (Math.abs(this.coords.usrCoords[0])>JXG.Math.eps)?this.isReal:false;  //Homogeneous coords: ideal point
            if (this.isReal) {
                if (wasReal!=this.isReal) { 
                    this.board.renderer.show(this); 
                    if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.show(this.label.content);
                }
                this.board.renderer.updatePoint(this);
            } else {
                if (wasReal!=this.isReal) { 
                    this.board.renderer.hide(this); 
                    if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.hide(this.label.content);
                }
            }
        } 

        /* Update the label if visible. */
        if(this.hasLabel && this.visProp.visible && this.label.content && this.label.content.visProp.visible && this.isReal) {
            this.label.content.update();
            this.board.renderer.updateText(this.label.content);
        }
                
        this.needsUpdate = false; 
        return this;
    },

    /**
     * Getter method for x, this is used by for CAS-points to access point coordinates.
     * @return User coordinate of point in x direction.
     * @type Number
     */
    X: function () {
        return this.coords.usrCoords[1];
    },

    /**
     * Getter method for y, this is used by CAS-points to access point coordinates.
     * @return User coordinate of point in y direction.
     * @type Number
     */
    Y: function () {
        return this.coords.usrCoords[2];
    },

    /**
     * Getter method for z, this is used by CAS-points to access point coordinates.
     * @return User coordinate of point in z direction.
     * @type Number
     */
    Z: function () {
        return this.coords.usrCoords[0];
    },

    /**
     * New evaluation of the function term. 
     * This is required for CAS-points: Their XTerm() method is overwritten in {@link #addConstraint}
     * @return User coordinate of point in x direction.
     * @type Number
     * @private
     */
    XEval: function () {
        return this.coords.usrCoords[1];
    },

    /**
     * New evaluation of the function term. 
     * This is required for CAS-points: Their YTerm() method is overwritten in {@link #addConstraint}
     * @return User coordinate of point in y direction.
     * @type Number
     * @private
     */
    YEval: function () {
        return this.coords.usrCoords[2];
    },

    /**
     * New evaluation of the function term. 
     * This is required for CAS-points: Their ZTerm() method is overwritten in {@link #addConstraint}
     * @return User coordinate of point in z direction.
     * @type Number
     * @private
     */
    ZEval: function () {
        return this.coords.usrCoords[0];
    },

    // documented in JXG.GeometryElement
    bounds: function () {
        return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1));
    },

    /**
     * Getter method for the distance to a second point, this is required for CAS-elements.
     * Here, function inlining seems to be worthwile  (for plotting).
     * @param {JXG.Point} point2 The point to which the distance shall be calculated.
     * @returns {Number} Distance in user coordinate to the given point
     */
    Dist: function(point2) {
        var sum,
            c = point2.coords.usrCoords,
            ucr = this.coords.usrCoords,
            f;
                        
        f = ucr[0]-c[0];
        sum = f*f;
        f = ucr[1]-c[1];
        sum += f*f;
        f = ucr[2]-c[2];
        sum += f*f;
        return Math.sqrt(sum);
    },

    snapToGrid: function () {
        return this.handleSnapToGrid();
    },

    /**
     * Move a point to its nearest grid point.
     * The function uses the coords object of the point as
     * its actual position.
     **/
    handleSnapToGrid: function() {
        var x, y, sX = this.visProp.snapsizex, sY = this.visProp.snapsizey;
                
        if (this.visProp.snaptogrid) {
            x = this.coords.usrCoords[1];
            y = this.coords.usrCoords[2];
                        
            if (sX <= 0 && this.board.defaultAxes && this.board.defaultAxes.x.defaultTicks) {
                sX = this.board.defaultAxes.x.defaultTicks.ticksDelta*(this.board.defaultAxes.x.defaultTicks.visProp.minorticks+1);
            }

            if (sY <= 0 && this.board.defaultAxes && this.board.defaultAxes.y.defaultTicks) {
                sY = this.board.defaultAxes.y.defaultTicks.ticksDelta*(this.board.defaultAxes.y.defaultTicks.visProp.minorticks+1);
            }

            // if no valid snap sizes are available, don't change the coords.
            if (sX > 0 && sY > 0) {
                this.coords.setCoordinates(JXG.COORDS_BY_USER, [Math.round(x/sX)*sX, Math.round(y/sY)*sY]);
            }
        }
        return this;
    },
  
    /**
     * Let a point snap to the nearest point in distance of 
     * {@link JXG.Point#attractorDistance}. 
     * The function uses the coords object of the point as
     * its actual position.
     **/
    handleSnapToPoints: function() {
        var el, pEl, pCoords, d=0.0, dMax=Infinity, c=null;
                
        if (this.visProp.snaptopoints) {
            for (el in this.board.objects) {
                pEl = this.board.objects[el];
                if (pEl.elementClass==JXG.OBJECT_CLASS_POINT && pEl!==this && pEl.visProp.visible) {
                    pCoords = JXG.Math.Geometry.projectPointToPoint(this, pEl, this.board); 
                    d = pCoords.distance(JXG.COORDS_BY_USER, this.coords);
                    if (d<this.visProp.attractordistance && d<dMax) {
                        dMax = d;
                        c = pCoords;
                    } 
                }
            }
            if (c!=null) {
                this.coords.setCoordinates(JXG.COORDS_BY_USER, c.usrCoords);
            }
        }

        return this;
    },
          
    /**
     * A point can change its type from free point to glider
     * and vice versa. If it is given an array of attractor elements 
     * (attribute attractors) and the attribute attractorDistance
     * then the pint will be made a glider if it less than attractorDistance
     * apart from one of its attractor elements.
     * If attractorDistance is equal to zero, the point stays in its
     * current form.
     **/
    handleAttractors: function() {
        var len = this.visProp.attractors.length,
            i, el, projCoords, d = 0.0;
                        
        if (this.visProp.attractordistance==0.0) {
            return;
        }

        for (i=0; i<len; i++) {
            el = JXG.getRef(this.board, this.visProp.attractors[i]);
            if (!JXG.exists(el) || el===this) {
                continue;
            }
            if (el.elementClass==JXG.OBJECT_CLASS_POINT) {
                projCoords = JXG.Math.Geometry.projectPointToPoint(this, el, this.board);
            } else if (el.elementClass==JXG.OBJECT_CLASS_LINE) {
                projCoords = JXG.Math.Geometry.projectPointToLine(this, el, this.board);
            } else if (el.elementClass==JXG.OBJECT_CLASS_CIRCLE) {
                projCoords = JXG.Math.Geometry.projectPointToCircle(this, el, this.board);
            } else if (el.elementClass==JXG.OBJECT_CLASS_CURVE) {
                projCoords = JXG.Math.Geometry.projectPointToCurve(this, el, this.board);
            } else if (el.type == JXG.OBJECT_TYPE_TURTLE) {
                projCoords = JXG.Math.Geometry.projectPointToTurtle(this, el, this.board);
            }
            d = projCoords.distance(JXG.COORDS_BY_USER, this.coords);
            if (d<this.visProp.attractordistance) {
                found = true;
                if (!(this.type==JXG.OBJECT_TYPE_GLIDER && this.slideObject==el)) {
                    this.makeGlider(el);
                }
                break;
            } else {
                if (el==this.slideObject && d>=this.visProp.snatchdistance) {
                    this.type = JXG.OBJECT_TYPE_POINT;
                }
            }
        }

        return this;
    },
        
    /**
     * Sets coordinates and calls the point's update() method.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinates <tt>(z, x, y)</tt> in screen/user units
     * @returns {JXG.Point}
     */
    setPositionDirectly: function (method, coords) {
        var i, dx, dy, dz, el, p,
            oldCoords = this.coords,
            newCoords;

        this.coords.setCoordinates(method, coords);
        this.handleSnapToGrid();
        this.handleSnapToPoints();
        this.handleAttractors();
                
        if(this.group.length > 0) {
            // Here used to be the udpate of the groups. I'm not sure why we don't need to execute
            // the else branch if there are groups defined on this point, hence I'll let the if live.
        } else {
            // Update the initial coordinates. This is needed for free points
            // that have a transformation bound to it.
            for (i = this.transformations.length - 1; i >= 0; i--) {
                if (method === JXG.COORDS_BY_SCREEN) {
                    newCoords = (new JXG.Coords(method, coords, this.board)).usrCoords;
                } else {
                    if (coords.length === 2) {
                        coords = [1].concat(coords);
                    }
                    newCoords = coords;
                }
                this.initialCoords.setCoordinates(JXG.COORDS_BY_USER, JXG.Math.matVecMult(JXG.Math.inverse(this.transformations[i].matrix), newCoords));
            }
            this.update();
        }

        return this;
    },

    /**
     * Translates the point by <tt>tv = (x, y)</tt>.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Number} tv (x, y)
     * @returns {JXG.Point}
     */
    setPositionByTransform: function (method, tv) {
        var t;

        tv = new JXG.Coords(method, tv, this.board);
        t = this.board.create('transform', tv.usrCoords.slice(1), {type:'translate'});

        if (this.transformations.length > 0 && this.transformations[this.transformations.length - 1].isNumericMatrix) {
            this.transformations[this.transformations.length - 1].melt(t);
        } else {
            this.addTransform(this, t);
        }

        //if (this.group.length == 0) {
        this.update();
        //}
        return this;
    },

    /**
     * Sets coordinates and calls the point's update() method.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinates in screen/user units
     * @returns {JXG.Point}
     */
    setPosition: function (method, coords) {
        return this.setPositionDirectly(method, coords);
    },

    /**
     * Sets the position of a glider relative to the defining elements of the {@link JXG.Point#slideObject}.
     * @param {Number} x
     * @returns {JXG.Point} Reference to the point element.
     */
    setGliderPosition: function (x) {
        if (this.type = JXG.OBJECT_TYPE_GLIDER) {
            this.position = x;
            this.board.update();
        }
                
        return this;
    },

    /**
     * Convert the point to glider and update the construction.
     * @param {String|Object} glideObject The Object the point will be bound to.
     */
    makeGlider: function (glideObject) {
        //var c = this.coords.usrCoords.slice(1);
        this.slideObject = JXG.getRef(this.board, glideObject);
        this.type = JXG.OBJECT_TYPE_GLIDER;
        this.elType = 'glider';
        this.visProp.snapwidth = -1;          // By default, deactivate snapWidth
        this.slideObject.addChild(this);
        this.isDraggable = true;

        this.generatePolynomial = function() {
            return this.slideObject.generatePolynomial(this);
        };

        this.updateGlider(); // Determine the initial value of this.position
        //this.moveTo(c);
        //this.prepareUpdate().update().updateRenderer();
        return this;
    },

    /**
     * Converts a glider into a free point.
     */
    free: function () {
        var anc, child;

        if (this.type !== JXG.OBJECT_TYPE_GLIDER) {
            if (!this.isDraggable) {
                this.isDraggable = true;
                this.type = JXG.OBJECT_TYPE_POINT;

                this.XEval = function () {
                    return this.coords.usrCoords[1];
                };

                this.YEval = function () {
                    return this.coords.usrCoords[2];
                };

                this.ZEval = function () {
                    return this.coords.usrCoords[0];
                };

                this.Xjc = null;
                this.Yjc = null;
            } else {
                return;
            }
        }

        for (anc in this.ancestors) {
            if (this.ancestors[anc].descendants[this.id])
                delete this.ancestors[anc].descendants[this.id];
          
            if (this.ancestors[anc].childElements[this.id])
                delete this.ancestors[anc].childElements[this.id];
                        
            for (child in this.descendants) {
                if (this.ancestors[anc].descendants[child])
                    delete this.ancestors[anc].descendants[child];
              
                if (this.ancestors[anc].childElements[child])
                    delete this.ancestors[anc].childElements[child];
            }
        }

        this.ancestors = []; // only remove the reference

        this.slideObject = null;
        this.elType = 'point';
        this.type = JXG.OBJECT_TYPE_POINT;
    },

    /**
     * Convert the point to CAS point and call update().
     * @param {Array} terms [[zterm], xterm, yterm] defining terms for the z, x and y coordinate.
     * The z-coordinate is optional and it is used for homogeneous coordinates.
     * The coordinates may be either <ul>
     *   <li>a JavaScript function,</li>
     *   <li>a string containing GEONExT syntax. This string will be converted into a JavaScript 
     *     function here,</li>
     *   <li>a Number</li>
     *   <li>a pointer to a slider object. This will be converted into a call of the Value()-method 
     *     of this slider.</li>
     *   </ul>
     * @see JXG.GeonextParser#geonext2JS
     */
    addConstraint: function (terms) {
        this.type = JXG.OBJECT_TYPE_CAS;
        var newfuncs = [],
            fs, i, v, t,
            what = ['X', 'Y'];
                
        this.isDraggable = false;
        for (i=0;i<terms.length;i++) {
            v = terms[i];
            if (typeof v=='string') {
                // Convert GEONExT syntax into  JavaScript syntax
                //t  = JXG.GeonextParser.geonext2JS(v, this.board);
                //newfuncs[i] = new Function('','return ' + t + ';');
                newfuncs[i] = this.board.jc.snippet(v, true, null, true);

                if (terms.length === 2) {
                    this[what[i] + 'jc'] = terms[i];
                }
            } else if (typeof v=='function') {
                newfuncs[i] = v;
            } else if (typeof v=='number') {
                newfuncs[i] = function(z){ return function() { return z; }; }(v);
            } else if (typeof v == 'object' && typeof v.Value == 'function') {    // Slider
                newfuncs[i] = (function(a) { return function() { return a.Value(); };})(v);
            }

            newfuncs[i].origin = v;
        }
        if (terms.length==1) { // Intersection function
            this.updateConstraint = function() { 
                    var c = newfuncs[0](); 
                    if (JXG.isArray(c)) {      // Array
                        this.coords.setCoordinates(JXG.COORDS_BY_USER,c);
                    } else {                   // Coords object
                        this.coords = c;
                    }
                };
        } else if (terms.length==2) { // Euclidean coordinates
            this.XEval = newfuncs[0];
            this.YEval = newfuncs[1];
            fs = 'this.coords.setCoordinates(' + JXG.COORDS_BY_USER + ',[this.XEval(),this.YEval()]);';
            this.updateConstraint = new Function('',fs);
        } else { // Homogeneous coordinates
            this.ZEval = newfuncs[0];
            this.XEval = newfuncs[1];
            this.YEval = newfuncs[2];
            fs = 'this.coords.setCoordinates(' + JXG.COORDS_BY_USER + ',[this.ZEval(),this.XEval(),this.YEval()]);';
            this.updateConstraint = new Function('',fs);
        }

        if (!this.board.isSuspendedUpdate) { this.prepareUpdate().update().updateRenderer(); }
        return this;
    },

    /**
     * Applies the transformations of the curve to {@link JXG.Point#baseElement}.
     * @returns {JXG.Point} Reference to this point object.
     */
    updateTransform: function () {
        if (this.transformations.length==0 || this.baseElement==null) {
            return this;
        }
        var c, i;

        if (this===this.baseElement) {      // case of bindTo
            c = this.transformations[0].apply(this.baseElement, 'self');
        } else {                           // case of board.create('point',[baseElement,transform]);
            c = this.transformations[0].apply(this.baseElement);
        }
        this.coords.setCoordinates(JXG.COORDS_BY_USER,c);
        for (i = 1; i < this.transformations.length; i++) {
            this.coords.setCoordinates(JXG.COORDS_BY_USER, this.transformations[i].apply(this));
        }
        return this;
    },

    /**
     * Add transformations to this point.
     * @param {JXG.GeometryElement} el TODO base element
     * @param {JXG.Transform|Array} transform Either one {@link JXG.Transform} or an array of {@link JXG.Transform}s.
     * @returns {JXG.Point} Reference to this point object.
     */
    addTransform: function (el, transform) {
        var i,
            list = JXG.isArray(transform) ? transform : [transform],
            len = list.length;

        if (this.transformations.length === 0) { // There is only one baseElement possible
            this.baseElement = el;
        }

        for (i = 0; i < len; i++) {
            this.transformations.push(list[i]);
        }
        return this;
    },

    /**
     * Animate the point. 
     * @param {Number} direction The direction the glider is animated. Can be +1 or -1.
     * @param {Number} stepCount The number of steps.
     * @name Glider#startAnimation
     * @see Glider#stopAnimation
     * @function
     */
    startAnimation: function(direction, stepCount) {
        if((this.type == JXG.OBJECT_TYPE_GLIDER) && (typeof this.intervalCode == 'undefined')) {
            this.intervalCode = window.setInterval('JXG.JSXGraph.boards[\'' + this.board.id + '\'].objects[\'' + this.id + '\']._anim(' 
                                                    + direction + ', ' + stepCount + ')', 250);
            if(typeof this.intervalCount == 'undefined')
                this.intervalCount = 0;
        }
        return this;
    },

    /**
     * Stop animation.
     * @name Glider#stopAnimation
     * @see Glider#startAnimation
     * @function
     */
    stopAnimation: function() {
        if(typeof this.intervalCode != 'undefined') {
            window.clearInterval(this.intervalCode);
            delete(this.intervalCode);
        }
        return this;
    },

    /**
     * Starts an animation which moves the point along a given path in given time.
     * @param {Array,function} path The path the point is moved on. This can be either an array of arrays containing x and y values of the points of
     * the path, or  function taking the amount of elapsed time since the animation has started and returns an array containing a x and a y value or NaN.
     * In case of NaN the animation stops.
     * @param {Number} time The time in milliseconds in which to finish the animation
     * @param {Object} [options] Optional settings for the animation:<ul><li>callback: A function that is called as soon as the animation is finished.</li></ul>
     * @returns {JXG.Point} Reference to the point.
     */
    moveAlong: function(path, time, options) {
        options = options || {};
        var interpath = [],
            delay = this.board.options.animationDelay,
            makeFakeFunction = function (i, j) {
                return function() {
                    return path[i][j];
                };
            },
            p = [], i, neville,
            steps = time/delay;

        if (JXG.isArray(path)) {
            for (i = 0; i < path.length; i++) {
                if (JXG.isPoint(path[i])) {
                    p[i] = path[i];
                } else {
                    p[i] = {
                        elementClass: JXG.OBJECT_CLASS_POINT,
                        X: makeFakeFunction(i, 0),
                        Y: makeFakeFunction(i, 1)
                    };
                }
            }

            time = time || 0;
            if (time === 0) {
                this.setPosition(JXG.COORDS_BY_USER, [p[p.length - 1].X(), p[p.length - 1].Y()]);
                return this.board.update(this);
            }

            neville = JXG.Math.Numerics.Neville(p);
            for (i = 0; i < steps; i++) {
                interpath[i] = [];
                interpath[i][0] = neville[0]((steps - i) / steps * neville[3]());
                interpath[i][1] = neville[1]((steps - i) / steps * neville[3]());
            }

            this.animationPath = interpath;
        } else if (JXG.isFunction(path)) {
            this.animationPath = path;
            this.animationStart = new Date().getTime();
        }
        this.animationCallback = options.callback;

        this.board.addAnimation(this);
        return this;
    },

    /**
     * Starts an animated point movement towards the given coordinates <tt>where</tt>. The animation is done after <tt>time</tt> milliseconds.
     * If the second parameter is not given or is equal to 0, setPosition() is called, see #setPosition.
     * @param {Array} where Array containing the x and y coordinate of the target location.
     * @param {Number} [time] Number of milliseconds the animation should last.
     * @param {Object} [options] Optional settings for the animation:<ul><li>callback: A function that is called as soon as the animation is finished.</li>
     * <li>effect: animation effects like speed fade in and out. possible values are '<>' for speed increase on start and slow down at the end (default)
     * and '--' for constant speed during the whole animation.</li></ul>
     * @returns {JXG.Point} Reference to itself.
     * @see #animate
     */
    moveTo: function(where, time, options) {
        where = new JXG.Coords(JXG.COORDS_BY_USER, where, this.board);

        if (typeof time == 'undefined' || time == 0 || (Math.abs(where.usrCoords[0] - this.coords.usrCoords[0]) > JXG.Math.eps)) {
            this.setPosition(JXG.COORDS_BY_USER, where.usrCoords);
            return this.board.update(this);
        }

        options = options || {};
                
        var delay = this.board.options.animationDelay,
            steps = Math.ceil(time/(delay * 1.0)),
            coords = new Array(steps+1),
            X = this.coords.usrCoords[1],
            Y = this.coords.usrCoords[2],
            dX = (where.usrCoords[1] - X),
            dY = (where.usrCoords[2] - Y),
            i,
            stepFun = function (i) {
                if (options.effect && options.effect == '<>') {
                    return Math.pow(Math.sin((i/(steps*1.0))*Math.PI/2.), 2);
                }
                return i/steps;
            };

        if(Math.abs(dX) < JXG.Math.eps && Math.abs(dY) < JXG.Math.eps) {
            return this;
        }

        for(i=steps; i>=0; i--) {
            coords[steps-i] = [where.usrCoords[0], X + dX * stepFun(i), Y+ dY * stepFun(i)];
        }

        this.animationPath = coords;
        this.animationCallback = options.callback;
        this.board.addAnimation(this);
        return this;
    },

    /**
     * Starts an animated point movement towards the given coordinates <tt>where</tt>. After arriving at <tt>where</tt> the point moves back to where it started.
     * The animation is done after <tt>time</tt> milliseconds.
     * @param {Array} where Array containing the x and y coordinate of the target location.
     * @param {Number} time Number of milliseconds the animation should last.
     * @param {Object} [options] Optional settings for the animation:<ul><li>callback: A function that is called as soon as the animation is finished.</li>
     * <li>effect: animation effects like speed fade in and out. possible values are '<>' for speed increase on start and slow down at the end (default)
     * and '--' for constant speed during the whole animation.</li><li>repeat: How often this animation should be repeated (default: 1)</li></ul>
     * @returns {JXG.Point} Reference to itself.
     * @see #animate
     */
    visit: function(where, time, options) {
        // support legacy interface where the third parameter was the number of repeats
        if (typeof options == 'number') {
            options = {repeat: options};
        } else {
            options = options || {};
            if(typeof options.repeat == 'undefined')
                options.repeat = 1;
        }

        var delay = this.board.options.animationDelay,
            steps = Math.ceil(time/(delay*options.repeat)),
            coords = new Array(options.repeat*(steps+1)),
            X = this.coords.usrCoords[1],
            Y = this.coords.usrCoords[2],
            dX = (where[0] - X),
            dY = (where[1] - Y),
            i, j,
            stepFun = function (i) {
                var x = (i < steps/2 ? 2*i/steps : 2*(steps-i)/steps);
                if (options.effect && options.effect == '<>') {
                    return Math.pow(Math.sin((x)*Math.PI/2.), 2);
                }
                return x;
            };

        for (j = 0; j < options.repeat; j++) {
            for(i = steps; i >= 0; i--) {
                coords[j*(steps+1) + steps-i] = [where[0], X + dX * stepFun(i), Y+ dY * stepFun(i)];
            }
        }
        this.animationPath = coords;
        this.animationCallback = options.callback;
        this.board.addAnimation(this);
        return this;
    },

    /**
     * Animates a glider. Is called by the browser after startAnimation is called.
     * @param {Number} direction The direction the glider is animated.
     * @param {Number} stepCount The number of steps.
     * @see #startAnimation
     * @see #stopAnimation
     * @private
     */
    _anim: function(direction, stepCount) {
        var distance, slope, dX, dY, alpha, startPoint,
            factor = 1, newX, radius;
                
        this.intervalCount++;
        if(this.intervalCount > stepCount)
            this.intervalCount = 0;
                
        if(this.slideObject.elementClass == JXG.OBJECT_CLASS_LINE) {
            distance = this.slideObject.point1.coords.distance(JXG.COORDS_BY_SCREEN, this.slideObject.point2.coords);
            slope = this.slideObject.getSlope();
            if(slope != 'INF') {
                alpha = Math.atan(slope);
                dX = Math.round((this.intervalCount/stepCount) * distance*Math.cos(alpha));
                dY = Math.round((this.intervalCount/stepCount) * distance*Math.sin(alpha));
            } else {
                dX = 0;
                dY = Math.round((this.intervalCount/stepCount) * distance);
            }
                        
            if(direction < 0) {
                startPoint = this.slideObject.point2;
                if(this.slideObject.point2.coords.scrCoords[1] - this.slideObject.point1.coords.scrCoords[1] > 0)
                    factor = -1;
                else if(this.slideObject.point2.coords.scrCoords[1] - this.slideObject.point1.coords.scrCoords[1] == 0) {
                    if(this.slideObject.point2.coords.scrCoords[2] - this.slideObject.point1.coords.scrCoords[2] > 0)
                        factor = -1;
                }
            } else {
                startPoint = this.slideObject.point1;
                if(this.slideObject.point1.coords.scrCoords[1] - this.slideObject.point2.coords.scrCoords[1] > 0)
                    factor = -1;
                else if(this.slideObject.point1.coords.scrCoords[1] - this.slideObject.point2.coords.scrCoords[1] == 0) {
                    if(this.slideObject.point1.coords.scrCoords[2] - this.slideObject.point2.coords.scrCoords[2] > 0)
                        factor = -1;
                }
            }
                        
            this.coords.setCoordinates(JXG.COORDS_BY_SCREEN, [startPoint.coords.scrCoords[1] + factor*dX, 
                                                              startPoint.coords.scrCoords[2] + factor*dY]);
        } else if(this.slideObject.elementClass == JXG.OBJECT_CLASS_CURVE) {
            if(direction > 0) {
                newX = Math.round(this.intervalCount/stepCount * this.board.canvasWidth);
            } else {
                newX = Math.round((stepCount - this.intervalCount)/stepCount * this.board.canvasWidth);
            }
            
            this.coords.setCoordinates(JXG.COORDS_BY_SCREEN, [newX, 0]);
            this.coords = JXG.Math.Geometry.projectPointToCurve(this, this.slideObject, this.board);
        } else if(this.slideObject.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
            if(direction < 0) {
                alpha = this.intervalCount/stepCount * 2*Math.PI;
            } else {
                alpha = (stepCount - this.intervalCount)/stepCount * 2*Math.PI;
            }

            radius = this.slideObject.Radius();

            this.coords.setCoordinates(JXG.COORDS_BY_USER, [this.slideObject.center.coords.usrCoords[1] + radius*Math.cos(alpha),
                                                            this.slideObject.center.coords.usrCoords[2] + radius*Math.sin(alpha)]);
        }
                
        this.board.update(this);
        return this;
    },

    /**
     * Set the style of a point. Used for GEONExT import and should not be used to set the point's face and size.
     * @param {Number} i Integer to determine the style.
     * @private
     */
    setStyle: function(i) {
        var facemap = [
                // 0-2
                'cross', 'cross', 'cross',
                // 3-6
                'circle', 'circle', 'circle', 'circle',
                // 7-9
                'square', 'square', 'square',
                // 10-12
                'plus', 'plus', 'plus'
            ], sizemap = [
                // 0-2
                2, 3, 4,
                // 3-6
                1, 2, 3, 4,
                // 7-9
                2, 3, 4,
                // 10-12
                2, 3, 4
            ];

        this.visProp.face = facemap[i];
        this.visProp.size = sizemap[i];

        this.board.renderer.changePointStyle(this);
        return this;
    },

    /**
     * All point faces can be defined with more than one name, e.g. a cross faced point can be given
     * by face equal to 'cross' or equal to 'x'. This method maps all possible values to fixed ones to
     * simplify if- and switch-clauses regarding point faces. The translation table is as follows:
     * <table>
     * <tr><th>Input</th><th>Output</th></tr>
     * <tr><td>cross, x</td><td>x</td></tr>
     * <tr><td>circle, o</td><td>o</td></tr>
     * <tr><td>square, []</td><td>[]</td></tr>
     * <tr><td>plus, +</td><td>+</td></tr>
     * <tr><td>diamond, &lt;&gt;</td><td>&lt;&gt;</td></tr>
     * <tr><td>triangleup, a, ^</td><td>A</td></tr>
     * <tr><td>triangledown, v</td><td>v</td></tr>
     * <tr><td>triangleleft, &lt;</td><td>&lt;</td></tr>
     * <tr><td>triangleright, &gt;</td><td>&gt;</td></tr>
     * </table>
     * @param {String} s A string which should determine a valid point face.
     * @returns {String} Returns a normalized string or undefined if the given string is not a valid
     * point face.
     */
    normalizeFace: function(s) {
        var map = {
                cross: 'x',
                x: 'x',
                circle: 'o',
                o: 'o',
                square: '[]',
                '[]': '[]',
                plus: '+',
                '+': '+',
                diamond: '<>',
                '<>': '<>',
                triangleup: '^',
                a: '^',
                '^': '^',
                triangledown: 'v',
                v: 'v',
                triangleleft: '<',
                '<': '<',
                triangleright: '>',
                '>': '>'
            };

        return map[s];
    },

    /**
     * Remove the point from the drawing. This only removes the SVG or VML node of the point and its label from the renderer, to remove
     * the object completely you should use {@link JXG.Board#removeObject}.
     */
    remove: function() {    
        if (this.hasLabel) {
            this.board.renderer.remove(this.board.renderer.getElementById(this.label.content.id));
        }
        this.board.renderer.remove(this.board.renderer.getElementById(this.id));
    },

    // documented in GeometryElement
    getTextAnchor: function() {
        return this.coords;
    },

    // documented in GeometryElement
    getLabelAnchor: function() {
        return this.coords;
    },

    /**
     * Set the face of a point element.
     * @param {string} f String which determines the face of the point. See {@link JXG.GeometryElement#face} for a list of available faces.
     * @see JXG.GeometryElement#face
     */
    face: function(f) {
        this.setProperty({face:f});
    },

    /**
     * Set the size of a point element
     * @param {int} s Integer which determines the size of the point.
     * @see JXG.GeometryElement#size
     */
    size: function(s) {
        this.setProperty({size:s});
    },

    // already documented in GeometryElement
    cloneToBackground: function() {
        var copy = {};

        copy.id = this.id + 'T' + this.numTraces;
        this.numTraces++;

        copy.coords = this.coords;
        copy.visProp = JXG.deepCopy(this.visProp, this.visProp.traceattributes, true);
        copy.visProp.layer = this.board.options.layer.trace;
        copy.elementClass = JXG.OBJECT_CLASS_POINT;
        copy.board = this.board;
        JXG.clearVisPropOld(copy);
                
        this.board.renderer.drawPoint(copy);
        this.traces[copy.id] = copy.rendNode;
                
        return this;
    },

    getParents: function () {
        var p = [this.Z(), this.X(), this.Y()];

        if (this.parents) {
            p = this.parents;
        }

        if (this.type == JXG.OBJECT_TYPE_GLIDER) {
            p = [this.X(), this.Y(), this.slideObject.id];

        }

        return p;
    }
});


/**
 * @class This element is used to provide a constructor for a general point. A free point is created if the given parent elements are all numbers
 * and the property fixed is not set or set to false. If one or more parent elements is not a number but a string containing a GEONE<sub>x</sub>T
 * constraint or a function the point will be considered as constrained). That means that the user won't be able to change the point's
 * position directly.
 * @pseudo
 * @description
 * @name Point
 * @augments JXG.Point
 * @constructor
 * @type JXG.Point
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {Number,string,function_Number,string,function_Number,string,function} z_,x,y Parent elements can be two or three elements of type number, a string containing a GEONE<sub>x</sub>T
 * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is
 * given by a number, the number determines the initial position of a free point. If given by a string or a function that coordinate will be constrained
 * that means the user won't be able to change the point's position directly by mouse because it will be calculated automatically depending on the string
 * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine euclidean coordinates, if three such
 * parent elements are given they will be interpreted as homogeneous coordinates.
 * @param {JXG.Point_JXG.Transformation} Point,Transformation A point can also be created providing a transformation. The resulting point is a clone of the base
 * point transformed by the given Transformation. {@see JXG.Transformation}.
 * @example
 * // Create a free point using affine euclidean coordinates 
 * var p1 = board.create('point', [3.5, 2.0]);
 * </pre><div id="672f1764-7dfa-4abc-a2c6-81fbbf83e44b" style="width: 200px; height: 200px;"></div>
 * <script type="text/javascript">
 *   var board = JXG.JSXGraph.initBoard('672f1764-7dfa-4abc-a2c6-81fbbf83e44b', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var p1 = board.create('point', [3.5, 2.0]);
 * </script><pre>
 * @example
 * // Create a constrained point using anonymous function 
 * var p2 = board.create('point', [3.5, function () { return p1.X(); }]);
 * </pre><div id="4fd4410c-3383-4e80-b1bb-961f5eeef224" style="width: 200px; height: 200px;"></div>
 * <script type="text/javascript">
 *   var fpex1_board = JXG.JSXGraph.initBoard('4fd4410c-3383-4e80-b1bb-961f5eeef224', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var fpex1_p1 = fpex1_board.create('point', [3.5, 2.0]);
 *   var fpex1_p2 = fpex1_board.create('point', [3.5, function () { return fpex1_p1.X(); }]);
 * </script><pre>
 * @example
 * // Create a point using transformations 
 * var trans = board.create('transform', [2, 0.5], {type:'scale'});
 * var p3 = board.create('point', [p2, trans]);
 * </pre><div id="630afdf3-0a64-46e0-8a44-f51bd197bb8d" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var fpex2_board = JXG.JSXGraph.initBoard('630afdf3-0a64-46e0-8a44-f51bd197bb8d', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var fpex2_trans = fpex2_board.create('transform', [2, 0.5], {type:'scale'});
 *   var fpex2_p2 = fpex2_board.create('point', [3.5, 2.0]);
 *   var fpex2_p3 = fpex2_board.create('point', [fpex2_p2, fpex2_trans]);
 * </script><pre>
 */
JXG.createPoint = function(board, parents, attributes) {
    var el, isConstrained = false, i, attr;

    attr = JXG.copyAttributes(attributes, board.options, 'point');

    for (i=0;i<parents.length;i++) {
        if (typeof parents[i]=='function' || typeof parents[i]=='string') {
            isConstrained = true;
        }
    }
    if (!isConstrained) {
        if ( (JXG.isNumber(parents[0])) && (JXG.isNumber(parents[1])) ) {
            el = new JXG.Point(board, parents, attr);
            if ( JXG.exists(attr["slideobject"]) ) {
                el.makeGlider(attr["slideobject"]);
            } else {
                el.baseElement = el; // Free point
            }
            el.isDraggable = true;
        } else if ( (typeof parents[0]=='object') && (typeof parents[1]=='object') ) { // Transformation
            el = new JXG.Point(board, [0,0], attr);
            el.addTransform(parents[0], parents[1]);
            el.isDraggable = false;

            //el.parents = [parents[0].id, parents[1].id];
            el.parents = [parents[0].id];
        }
        else {// Failure
            throw new Error("JSXGraph: Can't create point with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                            "\nPossible parent types: [x,y], [z,x,y], [point,transformation]");
        }

    } else {
        el = new JXG.Point(board, [NaN, NaN], attr);
        el.addConstraint(parents);
    }

    return el;
};

/**
 * @class This element is used to provide a constructor for a glider point. 
 * @pseudo
 * @description A glider is a point which lives on another geometric element like a line, circle, curve, turtle.
 * @name Glider
 * @augments JXG.Point
 * @constructor
 * @type JXG.Point
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {Number_Number_Number_JXG.GeometryElement} z_,x_,y_,GlideObject Parent elements can be two or three elements of type number and the object the glider lives on.
 * The coordinates are completely optional. If not given the origin is used. If you provide two numbers for coordinates they will be interpreted as affine euclidean
 * coordinates, otherwise they will be interpreted as homogeneous coordinates. In any case the point will be projected on the glide object.
 * @example
 * // Create a glider with user defined coordinates. If the coordinates are not on
 * // the circle (like in this case) the point will be projected onto the circle.
 * var p1 = board.create('point', [2.0, 2.0]);
 * var c1 = board.create('circle', [p1, 2.0]);
 * var p2 = board.create('glider', [2.0, 1.5, c1]);
 * </pre><div id="4f65f32f-e50a-4b50-9b7c-f6ec41652930" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var gpex1_board = JXG.JSXGraph.initBoard('4f65f32f-e50a-4b50-9b7c-f6ec41652930', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var gpex1_p1 = gpex1_board.create('point', [2.0, 2.0]);
 *   var gpex1_c1 = gpex1_board.create('circle', [gpex1_p1, 2.0]);
 *   var gpex1_p2 = gpex1_board.create('glider', [2.0, 1.5, gpex1_c1]);
 * </script><pre>
 * @example
 * // Create a glider with default coordinates (1,0,0). Same premises as above.
 * var p1 = board.create('point', [2.0, 2.0]);
 * var c1 = board.create('circle', [p1, 2.0]);
 * var p2 = board.create('glider', [c1]);
 * </pre><div id="4de7f181-631a-44b1-a12f-bc4d995609e8" style="width: 200px; height: 200px;"></div>
 * <script type="text/javascript">
 *   var gpex2_board = JXG.JSXGraph.initBoard('4de7f181-631a-44b1-a12f-bc4d995609e8', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var gpex2_p1 = gpex2_board.create('point', [2.0, 2.0]);
 *   var gpex2_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]);
 *   var gpex2_p2 = gpex2_board.create('glider', [gpex2_c1]);
 * </script><pre>
 */
JXG.createGlider = function(board, parents, attributes) {
    var el, 
        attr = JXG.copyAttributes(attributes, board.options, 'glider');
                
    if (parents.length === 1) {
        el = board.create('point', [0, 0], attr);
    } else {
        el = board.create('point', parents.slice(0, 2), attr);
    }

    // eltype is set in here
    el.makeGlider(parents[parents.length-1]);

    return el;
};

/**
 * @class This element is used to provide a constructor for an intersection point. 
 * @pseudo
 * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e.
 * an intersection point of the two elements.
 * @name Intersection
 * @augments JXG.Point
 * @constructor
 * @type JXG.Point
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2. i determines the
 * intersection point if two points are available: <ul>
 *   <li>i==0: use the positive square root,</li> 
 *   <li>i==1: use the negative square root.</li></ul>
 * @example
 * // Create an intersection point of circle and line
 * var p1 = board.create('point', [2.0, 2.0]);
 * var c1 = board.create('circle', [p1, 2.0]);
 * 
 * var p2 = board.create('point', [2.0, 2.0]);
 * var p3 = board.create('point', [2.0, 2.0]);
 * var l1 = board.create('line', [p2, p3]);
 * 
 * var i = board.create('intersection', [c1, l1, 0]);
 * </pre><div id="e5b0e190-5200-4bc3-b995-b6cc53dc5dc0" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var ipex1_board = JXG.JSXGraph.initBoard('e5b0e190-5200-4bc3-b995-b6cc53dc5dc0', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var ipex1_p1 = ipex1_board.create('point', [4.0, 4.0]);
 *   var ipex1_c1 = ipex1_board.create('circle', [ipex1_p1, 2.0]);
 *   var ipex1_p2 = ipex1_board.create('point', [1.0, 1.0]);
 *   var ipex1_p3 = ipex1_board.create('point', [5.0, 3.0]);
 *   var ipex1_l1 = ipex1_board.create('line', [ipex1_p2, ipex1_p3]);
 *   var ipex1_i = ipex1_board.create('intersection', [ipex1_c1, ipex1_l1, 0]);
 * </script><pre>
 */
JXG.createIntersectionPoint = function(board, parents, attributes) {
    var el,
        attr = JXG.copyAttributes(attributes, board.options, 'intersection'),
        func;


    // make sure we definitely have the indices
    parents.push(0, 0);
        
    el = board.create('point', [0,0,0], attr);
    func = new board.intersection(parents[0], parents[1], parents[2], parents[3], {point:el});
    el.addConstraint([func]);
        
    try {
        parents[0].addChild(el);
        parents[1].addChild(el);
    } catch (e) {
        throw new Error("JSXGraph: Can't create 'intersection' with parent types '" +
                                (typeof parents[0]) + "' and '" + (typeof parents[1])+ "'.");
    }

    el.elType = 'intersection';
    el.parents = [parents[0].id, parents[1].id, parents[2]];

    if (parents[3] != null) {
        el.parents.push(parents[3]);
    }

    el.generatePolynomial = function () {
        var poly1 = parents[0].generatePolynomial(el);
        var poly2 = parents[1].generatePolynomial(el);

        if((poly1.length == 0) || (poly2.length == 0))
            return [];
        else
            return [poly1[0], poly2[0]];
    };
        
    return el;
};

/**
 * @class This element is used to provide a constructor for the "other" intersection point.
 * @pseudo
 * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e.
 * an intersection point of the two elements. Additionally, one intersection point is provided. The function returns the other intersection point.
 * @name OtherIntersection
 * @augments JXG.Point
 * @constructor
 * @type JXG.Point
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_JXG.Point} el1,el2,p The result will be a intersection point on el1 and el2. i determines the
 * intersection point different from p: 
 * @example
 * // Create an intersection point of circle and line
 * var p1 = board.create('point', [2.0, 2.0]);
 * var c1 = board.create('circle', [p1, 2.0]);
 * 
 * var p2 = board.create('point', [2.0, 2.0]);
 * var p3 = board.create('point', [2.0, 2.0]);
 * var l1 = board.create('line', [p2, p3]);
 * 
 * var i = board.create('intersection', [c1, l1, 0]);
 * var j = board.create('otherintersection', [c1, l1, i]);
 * </pre><div id="45e25f12-a1de-4257-a466-27a2ae73614c" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var ipex2_board = JXG.JSXGraph.initBoard('45e25f12-a1de-4257-a466-27a2ae73614c', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var ipex2_p1 = ipex2_board.create('point', [4.0, 4.0]);
 *   var ipex2_c1 = ipex2_board.create('circle', [ipex2_p1, 2.0]);
 *   var ipex2_p2 = ipex2_board.create('point', [1.0, 1.0]);
 *   var ipex2_p3 = ipex2_board.create('point', [5.0, 3.0]);
 *   var ipex2_l1 = ipex2_board.create('line', [ipex2_p2, ipex2_p3]);
 *   var ipex2_i = ipex2_board.create('intersection', [ipex2_c1, ipex2_l1, 0], {name:'D'});
 *   var ipex2_j = ipex2_board.create('otherintersection', [ipex2_c1, ipex2_l1, ipex2_i], {name:'E'});
 * </script><pre>
 */
JXG.createOtherIntersectionPoint = function(board, parents, attributes) {
    var el;
    if (parents.length!=3 
        || !JXG.isPoint(parents[2]) 
        || (parents[0].elementClass != JXG.OBJECT_CLASS_LINE && parents[0].elementClass != JXG.OBJECT_CLASS_CIRCLE)
        || (parents[1].elementClass != JXG.OBJECT_CLASS_LINE && parents[1].elementClass != JXG.OBJECT_CLASS_CIRCLE) ) {
        // Failure
        throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '" + 
                        (typeof parents[0]) + "',  '" + (typeof parents[1])+ "'and  '" + (typeof parents[2]) + "'." +
                        "\nPossible parent types: [circle|line,circle|line,point]");
    }
    else {
        el = board.create('point', [board.otherIntersection(parents[0], parents[1], parents[2])], attributes);
    }
    el.elType = 'otherintersection';
    el.parents = [parents[0].id, parents[1].id, parents[2]];
        
    parents[0].addChild(el);
    parents[1].addChild(el);

    el.generatePolynomial = function () {
        var poly1 = parents[0].generatePolynomial(el);
        var poly2 = parents[1].generatePolynomial(el);

        if((poly1.length == 0) || (poly2.length == 0))
            return [];
        else
            return [poly1[0], poly2[0]];
    };
        
    return el;
};


JXG.JSXGraph.registerElement('point',JXG.createPoint);
JXG.JSXGraph.registerElement('glider', JXG.createGlider);
JXG.JSXGraph.registerElement('intersection', JXG.createIntersectionPoint);
JXG.JSXGraph.registerElement('otherintersection', JXG.createOtherIntersectionPoint);


/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview The geometry object Line is defined in this file. Line stores all
 * style and functional properties that are required to draw and move a line on
 * a board.
 */

/**
 * The Line class is a basic class for all kind of line objects, e.g. line, arrow, and axis. It is usually defined by two points and can
 * be intersected with some other geometry elements.
 * @class Creates a new basic line object. Do not use this constructor to create a line. Use {@link JXG.Board#create} with
 * type {@link Line}, {@link Arrow}, or {@link Axis} instead.
 * @constructor
 * @augments JXG.GeometryElement
 * @param {String,JXG.Board} board The board the new line is drawn on.
 * @param {Point} p1 Startpoint of the line.
 * @param {Point} p2 Endpoint of the line.
 * @param {String} id Unique identifier for this object. If null or an empty string is given,
 * an unique id will be generated by Board
 * @param {String} name Not necessarily unique name. If null or an
 * empty string is given, an unique name will be generated.
 * @param {Boolean} withLabel construct label, yes/no
 * @param {Number} layer display layer [0-9]
 * @see JXG.Board#generateName
 */
JXG.Line = function (board, p1, p2, attributes) {
    this.constructor(board, attributes, JXG.OBJECT_TYPE_LINE, JXG.OBJECT_CLASS_LINE);

    /**
     * Startpoint of the line. You really should not set this field directly as it may break JSXGraph's
     * udpate system so your construction won't be updated properly.
     * @type JXG.Point
     */
    this.point1 = JXG.getReference(this.board, p1);

    /**
     * Endpoint of the line. Just like {@link #point1} you shouldn't write this field directly.
     * @type JXG.Point
     */
    this.point2 = JXG.getReference(this.board, p2);

    /**
     * Array of ticks storing all the ticks on this line. Do not set this field directly and use
     * {@link JXG.Line#addTicks} and {@link JXG.Line#removeTicks} to add and remove ticks to and from the line.
     * @type Array
     * @see JXG.Ticks
     */
    this.ticks = [];

    /**
     * Reference of the ticks created automatically when constructing an axis.
     * @type JXG.Ticks
     * @see JXG.Ticks
     */
    this.defaultTicks = null;

    /**
    * If the line is the border of a polygon, the polygon object is stored, otherwise null.
    * @type JXG.Polygon
    * @default null
    * @private
    */
    this.parentPolygon = null;

    /* Register line at board */
    this.id = this.board.setId(this, 'L');
    this.board.renderer.drawLine(this);
    this.board.finalizeAdding(this);

    this.elType = 'line';

    /* Add arrow as child to defining points */
    this.point1.addChild(this);
    this.point2.addChild(this);


    this.updateStdform(); // This is needed in the following situation: 
                          // * the line is defined by three coordinates
                          // * and it will have a glider 
                          // * and board.suspendUpdate() has been called.

    // create Label
    this.createLabel();
};

JXG.Line.prototype = new JXG.GeometryElement;


JXG.extend(JXG.Line.prototype, /** @lends JXG.Line.prototype */ {
    /**
     * Checks whether (x,y) is near the line.
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @return {Boolean} True if (x,y) is near the line, False otherwise.
     */
    hasPoint: function (x, y) {
        // Compute the stdform of the line in screen coordinates.
        var c = [], s,
            v = [1, x, y],
            vnew,
            p1c, p2c, d, pos, i;

        c[0] = this.stdform[0] -
               this.stdform[1]*this.board.origin.scrCoords[1]/this.board.unitX+
               this.stdform[2]*this.board.origin.scrCoords[2]/this.board.unitY;
        c[1] = this.stdform[1]/this.board.unitX;
        c[2] = this.stdform[2]/(-this.board.unitY);

        /*
        
        // The point is too far away from the line
        // dist(v,vnew)^2 projective
        s = (v[1]-vnew[1])*(v[1]-vnew[1])+(v[2]-vnew[2])*(v[2]-vnew[2]);
        */

        s = JXG.Math.Geometry.distPointLine(v, c);
        if (isNaN(s) || s>this.board.options.precision.hasPoint) {
            return false;
        }

        if(this.visProp.straightfirst && this.visProp.straightlast) {
            return true;
        } else { // If the line is a ray or segment we have to check if the projected point is between P1 and P2.
            p1c = this.point1.coords;
            p2c = this.point2.coords;
            // Project the point orthogonally onto the line 
            vnew = [0, c[1], c[2]];
            vnew = JXG.Math.crossProduct(vnew, v); // Orthogonal line to c through v
            vnew = JXG.Math.crossProduct(vnew, c); // Intersect orthogonal line with line

            // Normalize the projected point
            vnew[1] /= vnew[0];
            vnew[2] /= vnew[0];
            vnew[0] = 1.0;
            
            vnew = (new JXG.Coords(JXG.COORDS_BY_SCREEN, vnew.slice(1), this.board)).usrCoords;
            d = p1c.distance(JXG.COORDS_BY_USER, p2c);
            p1c = p1c.usrCoords.slice(0);
            p2c = p2c.usrCoords.slice(0);
            if (d<JXG.Math.eps) {                  // The defining points are identical
                pos = 0.0;
            } else {
                /*
                * Handle the cases, where one of the defining points is an ideal point.
                * d is set to something close to infinity, namely 1/eps.
                * The ideal point is (temporarily) replaced by a finite point which has
                * distance d from the other point. 
                * This is accomplishrd by extracting the x- and y-coordinates (x,y)=:v of the ideal point.
                * v determines the direction of the line. v is normalized, i.e. set to length 1 by deividing through its length.
                * Finally, the new point is the sum of the other point and v*d.
                * 
                */
                if (d==Number.POSITIVE_INFINITY) {                       // At least one point is an ideal point
					d = 1.0/JXG.Math.eps;
                    if (Math.abs(p2c[0])<JXG.Math.eps) {                 // The second point is an ideal point
                        d /= JXG.Math.Geometry.distance([0,0,0], p2c);
                        p2c = [1, p1c[1]+p2c[1]*d, p1c[2]+p2c[2]*d];
                    } else {                                             // The first point is an ideal point
                        d /= JXG.Math.Geometry.distance([0,0,0], p1c);
                        p1c = [1, p2c[1]+p1c[1]*d, p2c[2]+p1c[2]*d];
                    }
                }
                i = 1;
                d = p2c[i] - p1c[i];
                if (Math.abs(d)<JXG.Math.eps) { 
                    i = 2; 
                    d = p2c[i] - p1c[i];
                }
                pos = (vnew[i] - p1c[i]) / d;
            }        
            if(!this.visProp.straightfirst && pos<0) {
                return false;
            }
            if(!this.visProp.straightlast && pos>1.0) {
                return false;
            }
            return true;
        }
    },

    /**
     * TODO description. maybe. already documented in geometryelement?
     * @private
     */
    update: function() {
        var funps;

        if (!this.needsUpdate) { return this; }
        
        if(this.constrained) {
            if(typeof this.funps != 'undefined') {
                funps = this.funps();
                if (funps && funps.length && funps.length === 2) {
                    this.point1 = funps[0];
                    this.point2 = funps[1];
                }
            } else {
                if (typeof this.funp1 === 'function') {
                    funps = this.funp1();
                    if (JXG.isPoint(funps)) {
                        this.point1 = funps;
                    } else if (funps && funps.length && funps.length === 2) {
                        this.point1.setPositionDirectly(JXG.COORDS_BY_USER, funps);
                    }
                }
                if (typeof this.funp2 === 'function') {
                    funps = this.funp2();
                    if (JXG.isPoint(funps)) {
                        this.point2 = funps;
                    } else if (funps && funps.length && funps.length === 2) {
                        this.point2.setPositionDirectly(JXG.COORDS_BY_USER, funps);
                    }
                }
            }
        }
        
        this.updateSegmentFixedLength();
        
        this.updateStdform();

        if(this.visProp.trace) {
            this.cloneToBackground(true);
        }
        return this;
    },

    /**
     * Update segments with fixed length and at least one movable point.
     * @private
     */
    updateSegmentFixedLength: function() {
        var d, dnew, d1, d2, drag1, drag2, x, y;
        // 
        if (!this.hasFixedLength) { return this; }

        // Compute the actual length of the segment
        d = this.point1.Dist(this.point2);
        // Determine the length the segment ought to have
        dnew = this.fixedLength();
        // Distances between the two points and their respective 
        // position before the update
        d1 = this.fixedLengthOldCoords[0].distance(JXG.COORDS_BY_USER, this.point1.coords);
        d2 = this.fixedLengthOldCoords[1].distance(JXG.COORDS_BY_USER, this.point2.coords);

        // If the position of the points or the fixed length function has been changed 
        // we have to work.
        if (d1>JXG.Math.eps || d2>JXG.Math.eps || d!=dnew) {
            drag1 = this.point1.isDraggable && (this.point1.type != JXG.OBJECT_TYPE_GLIDER) && !this.point1.visProp.fixed;
            drag2 = this.point2.isDraggable && (this.point2.type != JXG.OBJECT_TYPE_GLIDER) && !this.point2.visProp.fixed;

            // First case: the two points are different
            // Then we try to adapt the point that was not dragged
            // If this point can not be moved (e.g. because it is a glider)
            // we try move the other point
            if (d>JXG.Math.eps) {
                if ((d1>d2 && drag2) || 
                    (d1<=d2 && drag2 && !drag1)) {  
                    this.point2.setPositionDirectly(JXG.COORDS_BY_USER, 
                        [this.point1.X() + (this.point2.X()-this.point1.X())*dnew/d,
                        this.point1.Y() + (this.point2.Y()-this.point1.Y())*dnew/d]
                        );
                    this.point2.prepareUpdate().updateRenderer();
                } else if ((d1<=d2 && drag1) || 
                           (d1>d2 && drag1 && !drag2)) {  
                    this.point1.setPositionDirectly(JXG.COORDS_BY_USER, 
                        [this.point2.X() + (this.point1.X()-this.point2.X())*dnew/d,
                        this.point2.Y() + (this.point1.Y()-this.point2.Y())*dnew/d]
                        );
                    this.point1.prepareUpdate().updateRenderer();
                }
            // Second case: the two points are identical. In this situation
            // we choose a random direction.
            } else {
                x = Math.random()-0.5;
                y = Math.random()-0.5;
                d = Math.sqrt(x*x+y*y);
                if (drag2) {  
                    this.point2.setPositionDirectly(JXG.COORDS_BY_USER, 
                        [this.point1.X() + x*dnew/d,
                        this.point1.Y() + y*dnew/d]
                        );
                    this.point2.prepareUpdate().updateRenderer();
                } else if (drag1) {
                    this.point1.setPositionDirectly(JXG.COORDS_BY_USER, 
                        [this.point2.X() + x*dnew/d,
                        this.point2.Y() + y*dnew/d]
                        );
                    this.point1.prepareUpdate().updateRenderer();
                }
            }
            // Finally, we save the position of the two points.
            this.fixedLengthOldCoords[0].setCoordinates(JXG.COORDS_BY_USER, this.point1.coords.usrCoords);
            this.fixedLengthOldCoords[1].setCoordinates(JXG.COORDS_BY_USER, this.point2.coords.usrCoords);
        }
        return this;
    },
    
    /**
     * TODO description. already documented in geometryelement?
     * @private
     */
    updateStdform: function() {
        var v = JXG.Math.crossProduct(this.point1.coords.usrCoords, this.point2.coords.usrCoords);
        this.stdform[0] = v[0];
        this.stdform[1] = v[1];
        this.stdform[2] = v[2];
        this.stdform[3] = 0;
        this.normalize();
    },

    /**
     * Uses the boards renderer to update the line.
     * @private
     */
     updateRenderer: function () {
        var wasReal;

        if (this.needsUpdate && this.visProp.visible) {
            wasReal = this.isReal;
            this.isReal = (
                    !isNaN(this.point1.coords.usrCoords[1] + 
                           this.point1.coords.usrCoords[2] + 
                           this.point2.coords.usrCoords[1] + 
                           this.point2.coords.usrCoords[2]
                          ) 
                    && (JXG.Math.innerProduct(this.stdform,this.stdform,3)>=JXG.Math.eps*JXG.Math.eps) 
                    );
            if (this.isReal) {
                if (wasReal!=this.isReal) {
                    this.board.renderer.show(this);
                    if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.show(this.label.content);
                }
                this.board.renderer.updateLine(this);
            } else {
                if (wasReal!=this.isReal) {
                    this.board.renderer.hide(this);
                    if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.hide(this.label.content);
                }
            }

            //this.board.renderer.updateLine(this); // Why should we need this?
            this.needsUpdate = false;
        }

        /* Update the label if visible. */
        if(this.hasLabel && this.label.content.visProp.visible && this.isReal) {
            //this.label.setCoordinates(this.coords);
            this.label.content.update();
            //this.board.renderer.updateLabel(this.label);
            this.board.renderer.updateText(this.label.content);
        }
        return this;
    },

    /**
     * Used to generate a polynomial for a point p that lies on this line, i.e. p is collinear to {@link #point1}
     * and {@link #point2}.
     * @param p The point for that the polynomial is generated.
     * @return An array containing the generated polynomial.
     * @private
     */
    generatePolynomial: function (/** JXG.Point */ p) /** array */{
        var u1 = this.point1.symbolic.x,
            u2 = this.point1.symbolic.y,
            v1 = this.point2.symbolic.x,
            v2 = this.point2.symbolic.y,
            w1 = p.symbolic.x,
            w2 = p.symbolic.y;

        /*
         * The polynomial in this case is determined by three points being collinear:
         *
         *      U (u1,u2)      W (w1,w2)                V (v1,v2)
         *  ----x--------------x------------------------x----------------
         *
         *  The collinearity condition is
         *
         *      u2-w2       w2-v2
         *     -------  =  -------           (1)
         *      u1-w1       w1-v1
         *
         * Multiplying (1) with denominators and simplifying is
         *
         *    u2w1 - u2v1 + w2v1 - u1w2 + u1v2 - w1v2 = 0
         */

        return [['(',u2,')*(',w1,')-(',u2,')*(',v1,')+(',w2,')*(',v1,')-(',u1,')*(',w2,')+(',u1,')*(',v2,')-(',w1,')*(',v2,')'].join('')];
    },

    /**
     * Calculates the y intersect of the line.
     * @type Number
     * @return The y intersect.
     */
    getRise: function () {
        if (Math.abs(this.stdform[2])>=JXG.Math.eps) {
            return -this.stdform[0]/this.stdform[2];
        } else {
            return Infinity;
        }
    },

    /**
     * Calculates the slope of the line.
     * @type Number
     * @return The slope of the line or Infinity if the line is parallel to the y-axis.
     */
    getSlope: function () {
        if (Math.abs(this.stdform[2])>=JXG.Math.eps) {
            return -this.stdform[1]/this.stdform[2];
        } else {
            return Infinity;
        }
    },

    /**
     * Determines the angle between the positive x axis and the line.
     * @returns {Number}
     */
    getAngle: function () {
        return Math.atan2(this.point2.Y() - this.point1.Y(), this.point2.X() - this.point1.X());
    },

    /**
     * Determines whether the line is drawn beyond {@link #point1} and {@link #point2} and updates the line.
     * @param {Boolean} straightFirst True if the Line shall be drawn beyond {@link #point1}, false otherwise.
     * @param {Boolean} straightLast True if the Line shall be drawn beyond {@link #point2}, false otherwise.
     * @see #straightFirst
     * @see #straightLast
     * @private
     */
    setStraight: function (straightFirst, straightLast) {
        this.visProp.straightfirst = straightFirst;
        this.visProp.straightlast = straightLast;

        this.board.renderer.updateLine(this);
        return this;
    },

    // documented in geometry element
    getTextAnchor: function() {
        return new JXG.Coords(JXG.COORDS_BY_USER, [0.5*(this.point2.X() + this.point1.X()), 0.5*(this.point2.Y() + this.point1.Y())],this.board);
    },

    /**
     * Adjusts Label coords relative to Anchor. DESCRIPTION
     * @private
     */
    setLabelRelativeCoords: function(relCoords) {
        if (JXG.exists(this.label.content)) { 
            this.label.content.relativeCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [relCoords[0],-relCoords[1]], this.board);
        }
    },

    // documented in geometry element
    getLabelAnchor: function() {
        var x, y,
            fs = 0,
            sx = 0, 
            sy = 0,
            c1 = new JXG.Coords(JXG.COORDS_BY_USER, this.point1.coords.usrCoords, this.board),
            c2 = new JXG.Coords(JXG.COORDS_BY_USER, this.point2.coords.usrCoords, this.board);
        
        if (this.visProp.straightfirst || this.visProp.straightlast) {
            JXG.Math.Geometry.calcStraight(this, c1, c2, 0);
        } 
        c1 = c1.scrCoords;
        c2 = c2.scrCoords;

        if (!JXG.exists(this.label.content)) {
            return new JXG.Coords(JXG.COORDS_BY_SCREEN, [NaN, NaN], this.board);
        }

        switch (this.label.content.visProp.position) {
            case 'lft':
            case 'llft':
            case 'ulft':
                if (c1[1] <= c2[1]) {
                    x = c1[1]; 
                    y = c1[2];
                } else {
                    x = c2[1]; 
                    y = c2[2];
                }
                break;
            case 'rt':
            case 'lrt':
            case 'urt':
                if (c1[1] > c2[1]) {
                    x = c1[1]; 
                    y = c1[2];
                } else {
                    x = c2[1]; 
                    y = c2[2];
                }
                break;
            default:
                x = 0.5*(c1[1] + c2[1]);
                y = 0.5*(c1[2] + c2[2]);
        }

        if (this.visProp.straightfirst || this.visProp.straightlast) {
            if (JXG.exists(this.label.content)) {  // Does not exist during createLabel
                sx = parseFloat(this.label.content.visProp.offset[0]);
                sy = parseFloat(this.label.content.visProp.offset[1]);
                fs = this.label.content.visProp.fontsize;
            }

            if (Math.abs(x)<JXG.Math.eps) {
                x = sx;
            //} else if (Math.abs(x-this.board.canvasWidth) < JXG.Math.eps) {
            } else if (this.board.canvasWidth+JXG.Math.eps>x && x>this.board.canvasWidth-fs-JXG.Math.eps) {
                x = this.board.canvasWidth - sx - fs;
            } else {
                x += sx;
            }
            
            if (JXG.Math.eps+fs > y && y > -JXG.Math.eps) {
                y = sy + fs;
            } else if (this.board.canvasHeight+JXG.Math.eps > y && y > this.board.canvasHeight-fs-JXG.Math.eps) {
                y = this.board.canvasHeight - sy;
            } else {
                y += sy;
            }
        } 
        return new JXG.Coords(JXG.COORDS_BY_SCREEN, [x, y], this.board);
    },

    // documented in geometry element
    cloneToBackground: function() {
        var copy = {}, r, s, er;

        copy.id = this.id + 'T' + this.numTraces;
        copy.elementClass = JXG.OBJECT_CLASS_LINE;
        this.numTraces++;
        copy.point1 = this.point1;
        copy.point2 = this.point2;

        copy.stdform = this.stdform;

        copy.board = this.board;

        copy.visProp = JXG.deepCopy(this.visProp, this.visProp.traceattributes, true);
        copy.visProp.layer = this.board.options.layer.trace;
        JXG.clearVisPropOld(copy);

        s = this.getSlope();
        r = this.getRise();
        copy.getSlope = function() { return s; };
        copy.getRise = function() { return r; };

        er = this.board.renderer.enhancedRendering;
        this.board.renderer.enhancedRendering = true;
        this.board.renderer.drawLine(copy);
        this.board.renderer.enhancedRendering = er;
        this.traces[copy.id] = copy.rendNode;

        delete copy;

        return this;
    },

    /**
     * Add transformations to this line.
     * @param {JXG.Transform|Array} transform Either one {@link JXG.Transform} or an array of {@link JXG.Transform}s.
     * @returns {JXG.Line} Reference to this line object.
     */
    addTransform: function (transform) {
        var i,
            list = JXG.isArray(transform) ? transform : [transform],
            len = list.length;

        for (i = 0; i < len; i++) {
            this.point1.transformations.push(list[i]);
            this.point2.transformations.push(list[i]);
        }
        
        return this;
    },

    /**
     * Apply a translation by <tt>tv = (x, y)</tt> to the line.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} tv (x, y)
     * @returns {JXG.Line} Reference to this line object.
     */
    setPosition: function (method, tv) {
        var t;

        tv = new JXG.Coords(method, tv, this.board);
        t = this.board.create('transform', tv.usrCoords.slice(1), {type:'translate'});
        
        if (this.point1.transformations.length > 0 && this.point1.transformations[this.point1.transformations.length - 1].isNumericMatrix) {
            this.point1.transformations[this.point1.transformations.length - 1].melt(t);
        } else {
            this.point1.addTransform(this.point1, t);
        }
        if (this.point2.transformations.length > 0 && this.point2.transformations[this.point2.transformations.length - 1].isNumericMatrix) {
            this.point2.transformations[this.point2.transformations.length - 1].melt(t);
        } else {
            this.point2.addTransform(this.point2, t);
        }
        
        return this;
    },

    /**
     * Moves the line by the difference of two coordinates.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinates in screen/user units
     * @param {Array} oldcoords previous coordinates in screen/user units
     * @returns {JXG.Line}
     */
    setPositionDirectly: function (method, coords, oldcoords) {
        var dc, t, 
            c = new JXG.Coords(method, coords, this.board),
            oldc = new JXG.Coords(method, oldcoords, this.board);

        if (!this.point1.draggable() || !this.point2.draggable()) {
            return this;
        }

        dc = JXG.Math.Statistics.subtract(c.usrCoords, oldc.usrCoords);
        t = this.board.create('transform', dc.slice(1), {type:'translate'});
        t.applyOnce([this.point1, this.point2] );
        
        return this;
    },

    // see geometryelement.js
    snapToGrid: function () {
        if (this.visProp.snaptogrid) {
            this.point1.snapToGrid();
            this.point2.snapToGrid();
        }

        return this;
    },

    /**
     * Treat the line as parametric curve in homogeneous coordinates, where the parameter t runs from 0 to 1.
     * First we transform the interval [0,1] to [-1,1].
     * If the line has homogeneous coordinates [c,a,b] = stdform[] then the direction of the line is [b,-a].
     * Now, we take one finite point that defines the line, i.e. we take either point1 or point2 (in case the line is not the ideal line).
     * Let the coordinates of that point be [z, x, y].
     * Then, the curve runs linearly from 
     * [0, b, -a] (t=-1) to [z, x, y] (t=0)
     * and 
     * [z, x, y] (t=0) to [0, -b, a] (t=1)
     * 
     * @param {Number} t Parameter running from 0 to 1.
     * @returns {Number} X(t) x-coordinate of the line treated as parametric curve.
     * */
    X: function (t) {
        var b = this.stdform[2], x;
        
        x = (Math.abs(this.point1.coords.usrCoords[0])>JXG.Math.eps) ?
            this.point1.coords.usrCoords[1] : this.point2.coords.usrCoords[1];
        t = (t-0.5)*2.0;
        if (t<0.0) {
            t *= (-1);
            return (1.0-t)*x + t*b; 
        } else {
            return (1.0-t)*x - t*b; 
        }
    },
    
    /**
     * Treat the line as parametric curve in homogeneous coordinates. See {@link #X} for a detailed description.
     * @param {Number} t Parameter running from 0 to 1.
     * @returns {Number} Y(t) y-coordinate of the line treated as parametric curve.
     */
    Y: function (t) {
        var a = this.stdform[1], y;

        y = (Math.abs(this.point1.coords.usrCoords[0])>JXG.Math.eps) ?
            this.point1.coords.usrCoords[2] : this.point2.coords.usrCoords[2];
        t = (t-0.5)*2.0;
        if (t<0.0) {
            t *= (-1);
            return (1.0-t)*y - t*a; 
        } else {
            return (1.0-t)*y + t*a; 
        }
    },
    
    /**
     * Treat the line as parametric curve in homogeneous coordinates. See {@link #X} for a detailed description.
     * @param {Number} t Parameter running from 0 to 1.
     * @returns {Number} Z(t) z-coordinate of the line treated as parametric curve.
     */
    Z: function (t) {
        var z = (Math.abs(this.point1.coords.usrCoords[0])>JXG.Math.eps) ?
            this.point1.coords.usrCoords[0] : this.point2.coords.usrCoords[0];
        
        t = (t-0.5)*2.0;
        if (t<0.0) {
            t *= (-1);
        }
        return (1.0-t) * z;
    },

    
    /*
     * This is needed for GEONExT compatibility
     * @type Number
     * @return the distance between the two points defining the line
     */
    L: function() {
        return this.point1.Dist(this.point2);
    },

    /**
     * TODO circle?!? --michael
     * private or public? --michael
     * Treat the circle as parametric curve:
     * t runs from 0 to 1
     * @private
     */
    minX: function () {
        return 0.0;
    },

    /**
     * TODO circle?!? --michael
     * private or public? --michael
     * Treat the circle as parametric curve:
     * t runs from 0 to 1
     * @private
     */
    maxX: function () {
        return 1.0;
    },

    // documented in geometry element
    bounds: function () {
        var p1c = this.point1.coords.usrCoords,
            p2c = this.point2.coords.usrCoords;

        return [Math.min(p1c[1], p2c[1]), Math.max(p1c[2], p2c[2]), Math.max(p1c[1], p2c[1]), Math.min(p1c[2], p2c[2])];
    },

    /**
     * Adds ticks to this line. Ticks can be added to any kind of line: line, arrow, and axis.
     * @param {JXG.Ticks} ticks Reference to a ticks object which is describing the ticks (color, distance, how many, etc.).
     * @type String
     * @return Id of the ticks object.
     */
    addTicks: function(ticks) {
        if(ticks.id == '' || typeof ticks.id == 'undefined')
            ticks.id = this.id + '_ticks_' + (this.ticks.length+1);

        this.board.renderer.drawTicks(ticks);
        this.ticks.push(ticks);

        return ticks.id;
    },

    // documented in GeometryElement.js
    remove: function () {
        this.removeAllTicks();
        JXG.GeometryElement.prototype.remove.call(this);
    },

    /**
     * Removes all ticks from a line.
     */
    removeAllTicks: function() {
        var i, t;

        for(t = this.ticks.length; t > 0; t--) {
            this.removeTicks(this.ticks[t-1]);
        }

        this.ticks = new Array();
        this.board.update();
    },

    /**
     * Removes ticks identified by parameter named tick from this line.
     * @param {JXG.Ticks} tick Reference to tick object to remove.
     */
    removeTicks: function(tick) {
        var t, j;
        if(this.defaultTicks != null && this.defaultTicks == tick) {
            this.defaultTicks = null;
        }

        for(t = this.ticks.length; t > 0; t--) {
            if(this.ticks[t-1] == tick) {
                this.board.removeObject(this.ticks[t-1]);

                if (this.ticks[t-1].ticks) {
                    for(j = 0; j < this.ticks[t-1].ticks.length; j++) {
                        if(this.ticks[t-1].labels[j] != null) {
                            this.board.removeObject(this.ticks[t-1].labels[j]);
                        }
                    }
                }
                delete(this.ticks[t-1]);
                break;
            }
        }
    },

    hideElement: function () {
        var i;

        JXG.GeometryElement.prototype.hideElement.call(this);

        for (i = 0; i < this.ticks.length; i++) {
            this.ticks[i].hideElement();
        }
    },

    showElement: function () {
        var i;

        JXG.GeometryElement.prototype.showElement.call(this);

        for (i = 0; i < this.ticks.length; i++) {
            this.ticks[i].showElement();
        }
    }
});

/**
 * @class This element is used to provide a constructor for a general line. A general line is given by two points. By setting additional properties
 * a line can be used as an arrow and/or axis.
 * @pseudo
 * @description
 * @name Line
 * @augments JXG.Line
 * @constructor
 * @type JXG.Line
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array,function_JXG.Point,array,function} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of
 * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.
 * It is possible to provide a function returning an array or a point, instead of providing an array or a point.
 * @param {Number,function_Number,function_Number,function} c,a,b A line can also be created providing three numbers. The line is then described by
 * the set of solutions of the equation <tt>a*x+b*y+c*z = 0</tt>. It is possible to provide three functions returning numbers, too.
 * @param {function} f This function must return an array containing three numbers forming the line's homogeneous coordinates.
 * @example
 * // Create a line using point and coordinates/
 * // The second point will be fixed and invisible.
 * var p1 = board.create('point', [4.5, 2.0]);
 * var l1 = board.create('line', [p1, [1.0, 1.0]]);
 * </pre><div id="c0ae3461-10c4-4d39-b9be-81d74759d122" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var glex1_board = JXG.JSXGraph.initBoard('c0ae3461-10c4-4d39-b9be-81d74759d122', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var glex1_p1 = glex1_board.create('point', [4.5, 2.0]);
 *   var glex1_l1 = glex1_board.create('line', [glex1_p1, [1.0, 1.0]]);
 * </script><pre>
 * @example
 * // Create a line using three coordinates
 * var l1 = board.create('line', [1.0, -2.0, 3.0]);
 * </pre><div id="cf45e462-f964-4ba4-be3a-c9db94e2593f" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var glex2_board = JXG.JSXGraph.initBoard('cf45e462-f964-4ba4-be3a-c9db94e2593f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var glex2_l1 = glex2_board.create('line', [1.0, -2.0, 3.0]);
 * </script><pre>
 */
JXG.createLine = function(board, parents, attributes) {
    var el, p1, p2, i, attr,
        c = [],
        constrained = false,
        isDraggable;

    /**
     * The line is defined by two points or coordinates of two points.
     * In the latter case, the points are created.
     */
    if (parents.length == 2) {
        // point 1 given by coordinates
        if (JXG.isArray(parents[0]) && parents[0].length>1) { 
            attr = JXG.copyAttributes(attributes, board.options, 'line', 'point1');
            p1 = board.create('point', parents[0], attr);
        } else if (JXG.isString(parents[0]) || parents[0].elementClass == JXG.OBJECT_CLASS_POINT) {
            p1 =  JXG.getReference(board,parents[0]);
        } else if ((typeof parents[0] == 'function') && (parents[0]().elementClass == JXG.OBJECT_CLASS_POINT)) {
            p1 = parents[0]();
            constrained = true;
        } else if ((typeof parents[0] == 'function') && (parents[0]().length && parents[0]().length === 2)) {
            attr = JXG.copyAttributes(attributes, board.options, 'line', 'point1');
            p1 = JXG.createPoint(board, parents[0](), attr);
            constrained = true;
        } else
            throw new Error("JSXGraph: Can't create line with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                            "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");
        
        // point 2 given by coordinates
        if (JXG.isArray(parents[1]) && parents[1].length>1) { 
            attr = JXG.copyAttributes(attributes, board.options, 'line', 'point2');
            p2 = board.create('point', parents[1], attr);
        } else if (JXG.isString(parents[1]) || parents[1].elementClass == JXG.OBJECT_CLASS_POINT) {
            p2 =  JXG.getReference(board, parents[1]);
        } else if ((typeof parents[1] == 'function') && (parents[1]().elementClass == JXG.OBJECT_CLASS_POINT)) {
            p2 = parents[1]();
            constrained = true;
        } else if ((typeof parents[1] == 'function') && (parents[1]().length && parents[1]().length === 2)) {
            attr = JXG.copyAttributes(attributes, board.options, 'line', 'point2');
            p2 = JXG.createPoint(board, parents[1](), attr);
            constrained = true;
        } else
            throw new Error("JSXGraph: Can't create line with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                            "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");
        
        attr = JXG.copyAttributes(attributes, board.options, 'line');

        el = new JXG.Line(board, p1, p2, attr);
        if (constrained) {
        	el.constrained = true;
        	el.funp1 = parents[0];
        	el.funp2 = parents[1];
        } else {
            el.isDraggable = true;
        }

        if (!el.constrained) {
            el.parents = [p1.id, p2.id];
        }
    }
    /**
     * Line is defined by three homogeneous coordinates.
     * Also in this case points are created.
     */
    else if (parents.length==3) {
        // free line
        isDraggable = true;
        for (i=0;i<3;i++) {
            if (typeof parents[i]=='number') {
                c[i] = function(z){ return function() { return z; }; }(parents[i]);
            } else if (typeof parents[i]=='function') {
                c[i] = parents[i];
                isDraggable = false;
            } else {
                throw new Error("JSXGraph: Can't create line with parent types '" +
                    (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2])+ "'." +
                    "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");
            }
        }
        // point 1 is the midpoint between (0,c,-b) and point 2. => point1 is finite.
        attr = JXG.copyAttributes(attributes, board.options, 'line', 'point1');
        if (isDraggable) {
            p1 = board.create('point',[c[2]()*c[2]()+c[1]()*c[1](), c[2]()-c[1]()*c[0]()+c[2](), -c[1]()-c[2]()*c[0]()-c[1]()], attr);
        } else {
            p1 = board.create('point',[
                function() { return (0.0 + c[2]()*c[2]()+c[1]()*c[1]())*0.5;},
                function() { return (c[2]() - c[1]()*c[0]()+c[2]())*0.5;},
                function() { return (-c[1]() - c[2]()*c[0]()-c[1]())*0.5;}], attr);
        }
        /*
         */
        // point 2: (b^2+c^2,-ba+c,-ca-b)
        attr = JXG.copyAttributes(attributes, board.options, 'line', 'point2');
        if (isDraggable) {
            p2 = board.create('point',[c[2]()*c[2]()+c[1]()*c[1](), -c[1]()*c[0]()+c[2](), -c[2]()*c[0]()-c[1]()], attr);
        } else {
            p2 = board.create('point',[
                function() { return c[2]()*c[2]()+c[1]()*c[1]();},
                function() { return -c[1]()*c[0]()+c[2]();},
                function() { return -c[2]()*c[0]()-c[1]();}], attr);
        }

        // If the line will have a glider
        // and board.suspendUpdate() has been called, we
        // need to compute the initial position of the two points p1 and p2.
        p1.prepareUpdate().update();
        p2.prepareUpdate().update();
        attr = JXG.copyAttributes(attributes, board.options, 'line');
        el = new JXG.Line(board, p1, p2, attr);
        el.isDraggable = isDraggable;             // Not yet working, because the points are not draggable.

        if (isDraggable) {
            el.parents = [c[0](), c[1](), c[2]()];
        }
    }
    /**
     * The parent array contains a function which returns two points.
     */
    else if ((parents.length==1) && (typeof parents[0] == 'function') && (parents[0]().length == 2) &&
    		 (parents[0]()[0].elementClass == JXG.OBJECT_CLASS_POINT) && (parents[0]()[1].elementClass == JXG.OBJECT_CLASS_POINT)) {
    	var ps = parents[0]();
        attr = JXG.copyAttributes(attributes, board.options, 'line');
        el = new JXG.Line(board, ps[0], ps[1], attr);
        el.constrained = true;
        el.funps = parents[0];
    } else if ((parents.length==1) && (typeof parents[0] == 'function') && (parents[0]().length == 3) &&
    		 (typeof parents[0]()[0] === 'number') && (typeof parents[0]()[1] === 'number') && (typeof parents[0]()[2] === 'number')) {
        ps = parents[0];

        attr = JXG.copyAttributes(attributes, board.options, 'line', 'point1');
        p1 = board.create('point',[
            function () {
                var c = ps();
                return [
                    (0.0 + c[2]*c[2]+c[1]*c[1])*0.5,
                    (c[2] - c[1]*c[0]+c[2])*0.5,
                    (-c[1] - c[2]*c[0]-c[1])*0.5
                    ];
            }], attr);

        attr = JXG.copyAttributes(attributes, board.options, 'line', 'point2');
        p2 = board.create('point',[
            function () {
                var c = ps();
                return [
                    c[2]*c[2]+c[1]*c[1],
                    -c[1]*c[0]+c[2],
                    -c[2]*c[0]-c[1]
                    ];
            }], attr);

        attr = JXG.copyAttributes(attributes, board.options, 'line');
        el = new JXG.Line(board, p1, p2, attr);

        el.constrained = true;
        el.funps = parents[0];
    } else {
        throw new Error("JSXGraph: Can't create line with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");
    }
    
    return el;
};

JXG.JSXGraph.registerElement('line', JXG.createLine);

/**
 * @class This element is used to provide a constructor for a segment. 
 * It's strictly spoken just a wrapper for element {@link Line} with {@link JXG.Line#straightFirst}
 * and {@link JXG.Line#straightLast} properties set to false. If there is a third variable then the 
 * segment has a fixed length (which may be a function, too).
 * @pseudo
 * @description
 * @name Segment
 * @augments JXG.Line
 * @constructor
 * @type JXG.Line
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array_JXG.Point,array} point1, point2 Parent elements can be two elements either of type {@link JXG.Point} 
 * or array of numbers describing the
 * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.
  * @param {number,function} length (optional) The points are adapted - if possible - such that their distance 
  * has a this value.
* @see Line
 * @example
 * // Create a segment providing two points.
 *   var p1 = board.create('point', [4.5, 2.0]);
 *   var p2 = board.create('point', [1.0, 1.0]);
 *   var l1 = board.create('segment', [p1, p2]);
 * </pre><div id="d70e6aac-7c93-4525-a94c-a1820fa38e2f" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var slex1_board = JXG.JSXGraph.initBoard('d70e6aac-7c93-4525-a94c-a1820fa38e2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var slex1_p1 = slex1_board.create('point', [4.5, 2.0]);
 *   var slex1_p2 = slex1_board.create('point', [1.0, 1.0]);
 *   var slex1_l1 = slex1_board.create('segment', [slex1_p1, slex1_p2]);
 * </script><pre>
 * 
 * @example
 * // Create a segment providing two points.
 *   var p1 = board.create('point', [4.0, 1.0]);
 *   var p2 = board.create('point', [1.0, 1.0]);
 *   var l1 = board.create('segment', [p1, p2]);
 *   var p3 = board.create('point', [4.0, 2.0]);
 *   var p4 = board.create('point', [1.0, 2.0]);
 *   var l2 = board.create('segment', [p3, p4, 3]);
 *   var p5 = board.create('point', [4.0, 3.0]);
 *   var p6 = board.create('point', [1.0, 4.0]);
 *   var l3 = board.create('segment', [p5, p6, function(){ return l1.L();} ]);
 * </pre><div id="617336ba-0705-4b2b-a236-c87c28ef25be" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var slex2_board = JXG.JSXGraph.initBoard('617336ba-0705-4b2b-a236-c87c28ef25be', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var slex2_p1 = slex1_board.create('point', [4.0, 1.0]);
 *   var slex2_p2 = slex1_board.create('point', [1.0, 1.0]);
 *   var slex2_l1 = slex1_board.create('segment', [slex1_p1, slex1_p2]);
 *   var slex2_p3 = slex1_board.create('point', [4.0, 2.0]);
 *   var slex2_p4 = slex1_board.create('point', [1.0, 2.0]);
 *   var slex2_l2 = slex1_board.create('segment', [slex1_p3, slex1_p4, 3]);
 *   var slex2_p5 = slex1_board.create('point', [4.0, 2.0]);
 *   var slex2_p6 = slex1_board.create('point', [1.0, 2.0]);
 *   var slex2_l3 = slex1_board.create('segment', [slex1_p5, slex1_p6, function(){ return slex2_l1.L();}]);
 * </script><pre>
 * 
 */
JXG.createSegment = function(board, parents, attributes) {
    var el, i, attr;

    attributes.straightFirst = false;
    attributes.straightLast = false;
    attr = JXG.copyAttributes(attributes, board.options, 'segment');
    
    el = board.create('line', parents.slice(0,2), attr);
    
    if (parents.length==3) {
        el.hasFixedLength = true;
        if (JXG.isNumber(parents[2])) {
            el.fixedLength = function() { return parents[2]; };
        } else if (JXG.isFunction(parents[2])) {
            el.fixedLength = parents[2];
        }   else {
            throw new Error("JSXGraph: Can't create segment with third parent type '" + 
                        (typeof parents[2]) + "'." + 
                        "\nPossible third parent types: number or function");
        }
        el.fixedLengthOldCoords = [];
        el.fixedLengthOldCoords[0] = new JXG.Coords(JXG.COORDS_BY_USER, el.point1.coords.usrCoords.slice(1,3), board);
        el.fixedLengthOldCoords[1] = new JXG.Coords(JXG.COORDS_BY_USER, el.point2.coords.usrCoords.slice(1,3), board);
    }

    el.elType = 'segment';

    return el;
};

JXG.JSXGraph.registerElement('segment', JXG.createSegment);

/**
 * @class This element is used to provide a constructor for arrow, which is just a wrapper for element {@link Line} with {@link JXG.Line#straightFirst}
 * and {@link JXG.Line#straightLast} properties set to false and {@link JXG.Line#lastArrow} set to true.
 * @pseudo
 * @description
 * @name Arrow
 * @augments JXG.Line
 * @constructor
 * @type JXG.Line
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the
 * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.
 * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions
 * of the equation <tt>a*x+b*y+c*z = 0</tt>.
 * @see Line
 * @example
 * // Create an arrow providing two points.
 *   var p1 = board.create('point', [4.5, 2.0]);
 *   var p2 = board.create('point', [1.0, 1.0]);
 *   var l1 = board.create('arrow', [p1, p2]);
 * </pre><div id="1d26bd22-7d6d-4018-b164-4c8bc8d22ccf" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var alex1_board = JXG.JSXGraph.initBoard('1d26bd22-7d6d-4018-b164-4c8bc8d22ccf', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var alex1_p1 = alex1_board.create('point', [4.5, 2.0]);
 *   var alex1_p2 = alex1_board.create('point', [1.0, 1.0]);
 *   var alex1_l1 = alex1_board.create('arrow', [alex1_p1, alex1_p2]);
 * </script><pre>
 */
JXG.createArrow = function(board, parents, attributes) {
    var el;

    attributes['firstArrow'] = false;
    attributes['lastArrow'] = true;
    el = board.create('line', parents, attributes).setStraight(false, false);
    //el.setArrow(false, true);
    el.type = JXG.OBJECT_TYPE_VECTOR;
    el.elType = 'arrow';

    return el;
};

JXG.JSXGraph.registerElement('arrow', JXG.createArrow);

/**
 * @class This element is used to provide a constructor for an axis. It's strictly spoken just a wrapper for element {@link Line} with {@link JXG.Line#straightFirst}
 * and {@link JXG.Line#straightLast} properties set to true. Additionally {@link JXG.Line#lastArrow} is set to true and default {@link Ticks} will be created.
 * @pseudo
 * @description
 * @name Axis
 * @augments JXG.Line
 * @constructor
 * @type JXG.Line
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the
 * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.
 * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions
 * of the equation <tt>a*x+b*y+c*z = 0</tt>.
 * @example
 * // Create an axis providing two coord pairs.
 *   var l1 = board.create('axis', [[0.0, 1.0], [1.0, 1.3]]);
 * </pre><div id="4f414733-624c-42e4-855c-11f5530383ae" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var axex1_board = JXG.JSXGraph.initBoard('4f414733-624c-42e4-855c-11f5530383ae', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var axex1_l1 = axex1_board.create('axis', [[0.0, 1.0], [1.0, 1.3]]);
 * </script><pre>
 */
JXG.createAxis = function(board, parents, attributes) {
    var attr,
        el, 
        dist;

    // Arrays oder Punkte, mehr brauchen wir nicht.
    if ( (JXG.isArray(parents[0]) || JXG.isPoint(parents[0]) ) && (JXG.isArray(parents[1]) || JXG.isPoint(parents[1])) ) {
        attr = JXG.copyAttributes(attributes, board.options, 'axis');
        el = board.create('line', parents, attr);
        el.type = JXG.OBJECT_TYPE_AXIS;
        el.isDraggable = false;
        el.point1.isDraggable = false;
        el.point2.isDraggable = false;

        for (var els in el.ancestors)
            el.ancestors[els].type = JXG.OBJECT_TYPE_AXISPOINT;

        attr = JXG.copyAttributes(attributes, board.options, 'axis', 'ticks');
        if (JXG.exists(attr.ticksdistance)) {
            dist = attr.ticksdistance;
        } else if(JXG.isArray(attr.ticks)) {
            dist = attr.ticks;
        } else {
            dist = 1.0;
        }

        /**
         * The ticks attached to the axis.
         * @memberOf Axis.prototype
         * @name defaultTicks
         * @type JXG.Ticks
         */
        el.defaultTicks = board.create('ticks', [el, dist], attr);

        el.defaultTicks.dump = false;

        el.elType = 'axis';
        el.subs = {
            ticks: el.defaultTicks
        };
    }
    else
        throw new Error("JSXGraph: Can't create axis with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");

    return el;
};

JXG.JSXGraph.registerElement('axis', JXG.createAxis);

/**
 * @class With the element tangent the slope of a line, circle, or curve in a certain point can be visualized. A tangent is always constructed
 * by a glider on a line, circle, or curve and describes the tangent in the glider point on that line, circle, or curve.
 * @pseudo
 * @description
 * @name Tangent
 * @augments JXG.Line
 * @constructor
 * @type JXG.Line
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {Glider} g A glider on a line, circle, or curve.
 * @example
 * // Create a tangent providing a glider on a function graph
 *   var c1 = board.create('curve', [function(t){return t},function(t){return t*t*t;}]);
 *   var g1 = board.create('glider', [0.6, 1.2, c1]);
 *   var t1 = board.create('tangent', [g1]);
 * </pre><div id="7b7233a0-f363-47dd-9df5-4018d0d17a98" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var tlex1_board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-4018d0d17a98', {boundingbox: [-6, 6, 6, -6], axis: true, showcopyright: false, shownavigation: false});
 *   var tlex1_c1 = tlex1_board.create('curve', [function(t){return t},function(t){return t*t*t;}]);
 *   var tlex1_g1 = tlex1_board.create('glider', [0.6, 1.2, tlex1_c1]);
 *   var tlex1_t1 = tlex1_board.create('tangent', [tlex1_g1]);
 * </script><pre>
 */
JXG.createTangent = function(board, parents, attributes) {
    var p,
        c,
        g, f, i, j, el, tangent;

    if (parents.length==1) { // One arguments: glider on line, circle or curve
        p = parents[0];
        c = p.slideObject;
    } else if (parents.length==2) {     // Two arguments: (point,F"|conic) or (line|curve|circle|conic,point). // Not yet: curve!
        if (JXG.isPoint(parents[0])) {  // In fact, for circles and conics it is the polar.
            p = parents[0];
            c = parents[1];
        } else if (JXG.isPoint(parents[1])) {
            c = parents[0];
            p = parents[1];
        } else {
            throw new Error("JSXGraph: Can't create tangent with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                            "\nPossible parent types: [glider], [point,line|curve|circle|conic]");
        }
    } else {
        throw new Error("JSXGraph: Can't create tangent with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [glider], [point,line|curve|circle|conic]");
    }

    if (c.elementClass == JXG.OBJECT_CLASS_LINE) {
        tangent = board.create('line', [c.point1,c.point2], attributes);
    } else if (c.elementClass == JXG.OBJECT_CLASS_CURVE && !(c.type == JXG.OBJECT_TYPE_CONIC)) {
        if (c.visProp.curvetype!='plot') {
            g = c.X;
            f = c.Y;
            tangent = board.create('line', [
                    function(){ return -p.X()*board.D(f)(p.position)+p.Y()*board.D(g)(p.position);},
                    function(){ return board.D(f)(p.position);},
                    function(){ return -board.D(g)(p.position);}
                    ], attributes );
            p.addChild(tangent);
            // this is required for the geogebra reader to display a slope
            tangent.glider = p;
        } else {  // curveType 'plot'
            // equation of the line segment: 0 = y*(x1-x2) + x*(y2-y1) + y1*x2-x1*y2
            tangent = board.create('line', [
                    function(){ i=Math.floor(p.position);
                                if (i==c.numberPoints-1) i--;
                                if (i<0) return 1.0;
                                return c.Y(i)*c.X(i+1)-c.X(i)*c.Y(i+1);},
                    function(){ i=Math.floor(p.position);
                                if (i==c.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return c.Y(i+1)-c.Y(i);},
                    function(){ i=Math.floor(p.position);
                                if (i==c.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return c.X(i)-c.X(i+1);}
                    ], attributes );
            p.addChild(tangent);
            // this is required for the geogebra reader to display a slope
            tangent.glider = p;
        }
    } else if (c.type == JXG.OBJECT_TYPE_TURTLE) {
            tangent = board.create('line', [
                    function(){ i=Math.floor(p.position);
                                for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
                                    el = c.objects[j];
                                    if (el.type==JXG.OBJECT_TYPE_CURVE) {
                                        if (i<el.numberPoints) break;
                                        i-=el.numberPoints;
                                    }
                                }
                                if (i==el.numberPoints-1) i--;
                                if (i<0) return 1.0;
                                return el.Y(i)*el.X(i+1)-el.X(i)*el.Y(i+1);},
                    function(){ i=Math.floor(p.position);
                                for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
                                    el = c.objects[j];
                                    if (el.type==JXG.OBJECT_TYPE_CURVE) {
                                        if (i<el.numberPoints) break;
                                        i-=el.numberPoints;moveTo(funps);
                                    }
                                }
                                if (i==el.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return el.Y(i+1)-el.Y(i);},
                    function(){ i=Math.floor(p.position);
                                for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
                                    el = c.objects[j];
                                    if (el.type==JXG.OBJECT_TYPE_CURVE) {
                                        if (i<el.numberPoints) break;
                                        i-=el.numberPoints;
                                    }
                                }
                                if (i==el.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return el.X(i)-el.X(i+1);}
                    ], attributes );
            p.addChild(tangent);
            // this is required for the geogebra reader to display a slope
            tangent.glider = p;
    } else if (c.elementClass == JXG.OBJECT_CLASS_CIRCLE || c.type == JXG.OBJECT_TYPE_CONIC) {
        // If p is not on c, the tangent is the polar.
        // This construction should work on conics, too. p has to lie on c.
        tangent = board.create('line', [
                    function(){ return JXG.Math.matVecMult(c.quadraticform,p.coords.usrCoords)[0]; },
                    function(){ return JXG.Math.matVecMult(c.quadraticform,p.coords.usrCoords)[1]; },
                    function(){ return JXG.Math.matVecMult(c.quadraticform,p.coords.usrCoords)[2]; }
                ], attributes);

        p.addChild(tangent);
        // this is required for the geogebra reader to display a slope
        tangent.glider = p;
    }

    if (!JXG.exists(tangent)) {
        throw new Error('JSXGraph: Couldn\'t create tangent with the given parents.');
    }

    tangent.elType = 'tangent';
    tangent.parents = [];
    for (i = 0; i < parents.length; i++) {
        tangent.parents.push(parents[i].id);
    }

    return tangent;
};

/**
 * Register the element type tangent at JSXGraph
 * @private
 */
JXG.JSXGraph.registerElement('tangent', JXG.createTangent);
JXG.JSXGraph.registerElement('polar', JXG.createTangent);
// vim: et ts=4


/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/
/** 
 * @fileoverview In this file the class Group is defined, a class for
 * managing grouping of points.
 */
 
/**
 * Creates a new instance of Group.
 * @class In this class all group management is done.
 * @param {String} id Unique identifier for this object.  If null or an empty string is given,
 * an unique id will be generated by Board
 * @param {String} name Not necessarily unique name, displayed on the board.  If null or an
 * empty string is given, an unique name will be generated.
 * @constructor
 */
JXG.Group = function(board, id, name) {
    var number,
        objArray,
        i, obj, el;
        
    this.board = board;
    this.objects = {};
    number = this.board.numObjects;
    this.board.numObjects++;

    if ((id == '') || !JXG.exists(id)) {
        this.id = this.board.id + 'Group' + number;
    } else {
        this.id = id;
    }
    this.board.groups[this.id] = this;
 
    this.type = JXG.OBJECT_TYPE_POINT;
    this.elementClass = JXG.OBJECT_CLASS_POINT;                

    if ((name == '') || !JXG.exists(name)) {
        this.name = 'group_' + this.board.generateName(this);
    } else {
        this.name = name;
    }
    delete(this.type);

    if ( (arguments.length == 4) && (JXG.isArray(arguments[3])) ) {
        objArray = arguments[3];
    } else {
        objArray = Array.prototype.slice.call(arguments, 3);
    }

    for (i = 0; i < objArray.length; i++) {
        obj = JXG.getReference(this.board, objArray[i]);
        if( (!obj.visProp.fixed) && ( (obj.type == JXG.OBJECT_TYPE_POINT) || (obj.type == JXG.OBJECT_TYPE_GLIDER) ) ) {
            if (obj.group.length != 0) {
                this.addGroup(obj.group[obj.group.length-1]);
            } else {
                this.addPoint(obj);
            }
        }
    }

    this.suspendUpdate = false;
    this.dX = 0;
    this.dY = 0;
};

JXG.extend(JXG.Group.prototype, /** @lends JXG.Group.prototype */ {
    /**
     * Releases the group added to the points in this group, but only if this group is the last group.
     */
    ungroup: function() {
        var el;
        for (el in this.objects) {
            if (JXG.isArray(this.objects[el].point.group) && this.objects[el].point.group[this.objects[el].point.group.length-1] == this) {
                this.objects[el].point.group.pop();
            }
            this.removePoint(this.objects[el].point);
        }
        // Unregister the group from board
        // delete(this.board.groups[this.id]);  // Not sure if we should delete the group
    },
    
    suspendUpdate: function () {
        this.suspendUpdate = true;
    },
    
    unsuspendUpdate: function () {
        this.suspendUpdate = false;
    },

    /**
     * Sends an update to all group members.
     * @param {JXG.Point} point The point that caused the update.
     */
    update: function(point, dX, dY, dZ) {
        var obj = null,
            el;

        if (!this.suspendUpdate) {
            this.suspendUpdate = true;

            for (el in this.objects) {
                if (JXG.exists(this.board.objects[el])) {
                    obj = this.objects[el].point;
                    if (obj.id != point.id) {
                        obj.coords.setCoordinates(JXG.COORDS_BY_USER, [obj.coords.usrCoords[1] + dX, obj.coords.usrCoords[2] + dY]);
                    }
                    this.objects[el].point.prepareUpdate().update(false).updateRenderer();
                } else {
                    delete(this.objects[el]);
                }
            }

            this.suspendUpdate = false;
        }

        return this;
    },

    /**
     * Adds an Point to this group.
     * @param {JXG.Point} object The point added to the group.
     */
    addPoint: function(object) {
        this.objects[object.id] = {
            point: object,
            handler: function (ou, os) {
                this.update(object, object.coords.usrCoords[1] - ou[1], object.coords.usrCoords[2] - ou[2], object.coords.usrCoords[0] - ou[0]);
            }
        };
        object.coords.on('update', this.objects[object.id].handler, this);
    },

    /**
     * Adds multiple points to this group.
     * @param {Array} objects An array of points to add to the group.
     */
    addPoints: function(objects) {
        var p;
        
        for (p = 0; p < objects.length; p++) {
            this.addPoint(objects[p]);
        }
    },

    /**
     * Adds all points in a group to this group.
     * @param {JXG.Point} group The group added to this group.
     */
    addGroup: function(group) {
        var el;
        
        for (el in group.objects) {
            this.addPoint(group.objects[el].point);
        }
    },

    /**
     * Removes a point from the group.
     * @param {JXG.Point} point
     */
    removePoint: function (point) {
        var i;

        this.objects[point.id].point.coords.off('update', this.objects[point.id].handler);
        delete this.objects[point.id];
    },

    setProperty: function () {
        var el;

        for (el in this.objects) {
            this.objects[el].point.setProperty.apply(this.objects[el].point, arguments);
        }
    }
});

/**
 * Groups points.
 * @param {JXG.Board} board The board the points are on.
 * @param {Array} parents Array of points to group.
 * @param {Object} attributes Visual properties.
 * @type JXG.Group
 * @return An object of type JXG.Group.
 */
JXG.createGroup = function(board, parents, attributes) {
    var i, g = new JXG.Group(board, attributes["id"], attributes["name"], parents);

    g.elType = 'group';

    g.parents = [];
    for (i = 0; i < parents.length; i++) {
        g.parents.push(parents[i].id);
    }

    return g;
};

JXG.JSXGraph.registerElement('group', JXG.createGroup);


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.

*/
    
/**
 * @fileoverview The geometry object Circle is defined in this file. Circle stores all
 * style and functional properties that are required to draw and move a circle on
 * a board.
 * @author graphjs
 * @version 0.1
 */

/**
 * A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius.
 * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function,
 * line, or circle). 
 * @class Creates a new circle object. Do not use this constructor to create a circle. Use {@link JXG.Board#create} with
 * type {@link Circle} instead.  
 * @constructor
 * @augments JXG.GeometryElement
 * @param {String,JXG.Board} board The board the new circle is drawn on.
 * @param {String} method Can be 
 * <ul><li> <b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li>
 * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius in user units</li>
 * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line</li>
 * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle</li></ul>
 * The parameters p1, p2 and radius must be set according to this method parameter.
 * @param {JXG.Point} p1 center of the circle.
 * @param {JXG.Point,JXG.Line,JXG.Circle} p2 Can be
 *<ul><li>a point on the circle if method is 'twoPoints'</li>
 <li>a line if the method is 'pointLine'</li>
 <li>a circle if the method is 'pointCircle'</li></ul>
 * @param {float} radius Only used when method is set to 'pointRadius'. Must be a given radius in user units.
 * @param {String} id Unique identifier for this object. If null or an empty string is given,
 * an unique id will be generated by Board
 * @param {String} name Not necessarily unique name. If null or an
 * empty string is given, an unique name will be generated.
 * @see JXG.Board#generateName
 */            

JXG.Circle = function (board, method, par1, par2, attributes) {
    /* Call the constructor of GeometryElement */
    this.constructor(board, attributes, JXG.OBJECT_TYPE_CIRCLE, JXG.OBJECT_CLASS_CIRCLE);


    //this.type = JXG.OBJECT_TYPE_CIRCLE;
    //this.elementClass = JXG.OBJECT_CLASS_CIRCLE;

    //this.init(board, attributes);
    
    /**
     * Stores the given method.
     * Can be 
     * <ul><li><b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li>
     * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius given in user units or as term.</li>
     * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line.</li>
     * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle.</li></ul>
     * @type string
     * @see #center
     * @see #point2
     * @see #radius
     * @see #line
     * @see #circle
     */
    this.method = method;

    // this is kept so existing code won't ne broken
    this.midpoint = JXG.getReference(this.board, par1);

    /**
     * The circles center. Do not set this parameter directly as it will break JSXGraph's update system.
     * @type JXG.Point
     */
    this.center = JXG.getReference(this.board, par1);
    
    /** Point on the circle only set if method equals 'twoPoints'. Do not set this parameter directly as it will break JSXGraph's update system.
     * @type JXG.Point
     * @see #method
     */
    this.point2 = null;
    
    /** Radius of the circle
     * only set if method equals 'pointRadius'
     * @type Number
     * @default null
     * @see #method     
     */    
    this.radius = 0;
    
    /** Line defining the radius of the circle given by the distance from the startpoint and the endpoint of the line
     * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system.
     * @type JXG.Line
     * @default null
     * @see #method     
     */    
    this.line = null;
    
    /** Circle defining the radius of the circle given by the radius of the other circle
     * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system.
     * @type JXG.Circle
     * @default null
     * @see #method     
     */     
    this.circle = null;

    if(method == 'twoPoints') {
        this.point2 = JXG.getReference(board,par2);
        // this.point2.addChild(this); // See below. Here, the id of this is not determined.
        this.radius = this.Radius(); 
    }
    else if(method == 'pointRadius') {
        this.gxtterm = par2;
        this.updateRadius = JXG.createFunction(par2, this.board, null, true);  // Converts GEONExT syntax into JavaScript syntax
        this.updateRadius();                        // First evaluation of the graph  
    }
    else if(method == 'pointLine') {
        // dann ist p2 die Id eines Objekts vom Typ Line!
        this.line = JXG.getReference(board, par2);
        this.radius = this.line.point1.coords.distance(JXG.COORDS_BY_USER, this.line.point2.coords);    
    }
    else if(method == 'pointCircle') {
        // dann ist p2 die Id eines Objekts vom Typ Circle!
        this.circle = JXG.getReference(board, par2);
        this.radius = this.circle.Radius();     
    } 
    
    // create Label
    this.id = this.board.setId(this, 'C');
    this.board.renderer.drawEllipse(this);
    this.board.finalizeAdding(this);

    this.createGradient();
    this.elType = 'circle';
    this.createLabel();

    this.center.addChild(this);
    
    if(method == 'pointRadius') {
        this.notifyParents(par2);
    } else if(method == 'pointLine') {
        this.line.addChild(this);
    } else if(method == 'pointCircle') {
        this.circle.addChild(this);
    }  else if(method == 'twoPoints') {
        this.point2.addChild(this);
    }

    this.methodMap = JXG.deepCopy(this.methodMap, {
        setRadius: 'setRadius',
        getRadius: 'getRadius',
        radius: 'Radius'
    });
};
JXG.Circle.prototype = new JXG.GeometryElement;

JXG.extend(JXG.Circle.prototype, /** @lends JXG.Circle.prototype */ {

    /**
     * Checks whether (x,y) is near the circle.
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @returns {Boolean} True if (x,y) is near the circle, False otherwise.
     * @private
     */
    hasPoint: function (x, y) {
        var prec = this.board.options.precision.hasPoint/(this.board.unitX),
            mp = this.center.coords.usrCoords,
            p = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board),
            r = this.Radius();

        var dist = Math.sqrt((mp[1]-p.usrCoords[1])*(mp[1]-p.usrCoords[1]) + (mp[2]-p.usrCoords[2])*(mp[2]-p.usrCoords[2]));
        if (this.visProp.hasinnerpoints) {
            return (dist < r + prec);
        } else {
            return (Math.abs(dist-r) < prec);
        }
        //return (dist <= r + prec);
    },

    /**
     * Used to generate a polynomial for a point p that lies on this circle.
     * @param p The point for that the polynomial is generated.
     * @returns {Array} An array containing the generated polynomial.
     * @private
     */
    generatePolynomial: function (p) {
        /*
         * We have four methods to construct a circle:
         *   (a) Two points
         *   (b) center and radius
         *   (c) center and radius given by length of a segment
         *   (d) center and radius given by another circle
         *
         * In case (b) we have to distinguish two cases:
         *  (i)  radius is given as a number
         *  (ii) radius is given as a function
         * In the latter case there's no guarantee the radius depends on other geometry elements
         * in a polynomial way so this case has to be omitted.
         *
         * Another tricky case is case (d):
         * The radius depends on another circle so we have to cycle through the ancestors of each circle
         * until we reach one that's radius does not depend on another circles radius.
         *
         *
         * All cases (a) to (d) vary only in calculation of the radius. So the basic formulae for
         * a glider G (g1,g2) on a circle with center M (m1,m2) and radius r is just:
         *
         *     (g1-m1)^2 + (g2-m2)^2 - r^2 = 0
         *
         * So the easiest case is (b) with a fixed radius given as a number. The other two cases (a)
         * and (c) are quite the same: Euclidean distance between two points A (a1,a2) and B (b1,b2),
         * squared:
         *
         *     r^2 = (a1-b1)^2 + (a2-b2)^2
         *
         * For case (d) we have to cycle recursively through all defining circles and finally return the
         * formulae for calculating r^2. For that we use JXG.Circle.symbolic.generateRadiusSquared().
         */

        var m1 = this.center.symbolic.x;
        var m2 = this.center.symbolic.y;
        var g1 = p.symbolic.x;
        var g2 = p.symbolic.y;

        var rsq = this.generateRadiusSquared();

        /* No radius can be calculated (Case b.ii) */
        if (rsq == '')
            return [];

        var poly = '((' + g1 + ')-(' + m1 + '))^2 + ((' + g2 + ')-(' + m2 + '))^2 - (' + rsq + ')';
        return [poly];
    },

    /**
     * Generate symbolic radius calculation for loci determination with Groebner-Basis algorithm.
     * @returns {String} String containing symbolic calculation of the circle's radius or an empty string
     * if the radius can't be expressed in a polynomial equation.
     * @private
     */
    generateRadiusSquared: function () {
        /*
         * Four cases:
         *
         *   (a) Two points
         *   (b) center and radius
         *   (c) center and radius given by length of a segment
         *   (d) center and radius given by another circle
         */

        var rsq = '',
            m1, m2, p1, p2, q1, q2;

        if (this.method == "twoPoints") {
            m1 = this.center.symbolic.x;
            m2 = this.center.symbolic.y;
            p1 = this.point2.symbolic.x;
            p2 = this.point2.symbolic.y;

            rsq = '((' + p1 + ')-(' + m1 + '))^2 + ((' + p2 + ')-(' + m2 + '))^2';
        } else if (this.method == "pointRadius") {
            if (typeof(this.radius) == 'number')
                rsq = '' + this.radius*this.radius;
        } else if (this.method == "pointLine") {
            p1 = this.line.point1.symbolic.x;
            p2 = this.line.point1.symbolic.y;

            q1 = this.line.point2.symbolic.x;
            q2 = this.line.point2.symbolic.y;

            rsq = '((' + p1 + ')-(' + q1 + '))^2 + ((' + p2 + ')-(' + q2 + '))^2';
        } else if (this.method == "pointCircle") {
            rsq = this.circle.Radius();
        }

        return rsq;
    },

    /**
     * Uses the boards renderer to update the circle.
     */
    update: function () {
        if (this.needsUpdate) {
            if(this.visProp.trace) {
                this.cloneToBackground(true);
            }   

            if(this.method == 'pointLine') {
                this.radius = this.line.point1.coords.distance(JXG.COORDS_BY_USER, this.line.point2.coords);
            }
            else if(this.method == 'pointCircle') {
                this.radius = this.circle.Radius();
            }
            else if(this.method == 'pointRadius') {
                this.radius = this.updateRadius();
            }
            //if (true||!this.board.geonextCompatibilityMode) {
            this.updateStdform();
            this.updateQuadraticform();
            //}
        }
        return this;
    },

    /**
     * TODO description
     * @private
     */
    updateQuadraticform: function () {
        var m = this.center,
            mX = m.X(), mY = m.Y(), r = this.Radius();
        this.quadraticform = [[mX*mX+mY*mY-r*r,-mX,-mY],
            [-mX,1,0],
            [-mY,0,1]
        ];
    },

    /**
     * TODO description
     * @private
     */
    updateStdform: function () {
        this.stdform[3] = 0.5;
        this.stdform[4] = this.Radius();
        this.stdform[1] = -this.center.coords.usrCoords[1];
        this.stdform[2] = -this.center.coords.usrCoords[2];
        this.normalize();
    },

    /**
     * Uses the boards renderer to update the circle.
     * @private
     */
    updateRenderer: function () {
        if (this.needsUpdate && this.visProp.visible) {
            var wasReal = this.isReal;
            this.isReal = (!isNaN(this.center.coords.usrCoords[1] + this.center.coords.usrCoords[2] + this.Radius())) && this.center.isReal;
            if (this.isReal) {
                if (wasReal!=this.isReal) {
                    this.board.renderer.show(this);
                    if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.show(this.label.content);
                }
                this.board.renderer.updateEllipse(this);
            } else {
                if (wasReal!=this.isReal) {
                    this.board.renderer.hide(this);
                    if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.hide(this.label.content);
                }
            }
            this.needsUpdate = false;
        }

        /* Update the label if visible. */
        if(this.hasLabel && this.label.content.visProp.visible && this.isReal) {
            //this.label.setCoordinates(this.coords);
            this.label.content.update();
            //this.board.renderer.updateLabel(this.label);
            this.board.renderer.updateText(this.label.content);
        }
    },

    /**
     * TODO description
     * @param contentStr TODO type&description
     * @private
     */
    notifyParents: function (contentStr) {
        if (typeof contentStr == 'string')
            JXG.GeonextParser.findDependencies(this,contentStr+'',this.board);
    },

    /**
     * Set a new radius, then update the board.
     * @param {String|Number|function} r A string, function or number describing the new radius.
     * @returns {JXG.Circle} Reference to this circle
     */
    setRadius: function (r) {
        this.updateRadius = JXG.createFunction(r, this.board, null, true);
        this.board.update();

        return this;
    },

    /**
     * Calculates the radius of the circle.
     * @param {String|Number|function} [value] Set new radius
     * @returns {Number} The radius of the circle
     */
    Radius: function (value) {
        if (JXG.exists(value)) {
            this.setRadius(value);
            return this.Radius();
        }

        if(this.method == 'twoPoints') {
            if (JXG.Math.Geometry.distance(this.point2.coords.usrCoords,[0,0,0])==0.0 || 
                JXG.Math.Geometry.distance(this.center.coords.usrCoords,[0,0,0])==0.0) {
                return NaN;
            } else {
                return this.center.Dist(this.point2);
            }
        }
        else if(this.method == 'pointLine' || this.method == 'pointCircle') {
            return this.radius;
        }
        else if(this.method == 'pointRadius') {
            return this.updateRadius();
        }
    },

    /**
     * @deprecated
     */
    getRadius: function () {
        return this.Radius();
    },

    // documented in geometry element
    getTextAnchor: function () {
        return this.center.coords;
    },

    // documented in geometry element
    getLabelAnchor: function () {
        var r = this.Radius(),
            c = this.center.coords.usrCoords,
            x, y;

        switch (this.visProp.label.position) {
            case 'lft':
                x = c[1] - r; y = c[2]; break;
            case 'llft':
                x = c[1] - Math.sqrt(0.5)*r; y = c[2] - Math.sqrt(0.5)*r; break;
            case 'rt':
                x = c[1] + r; y = c[2]; break;
            case 'lrt':
                x = c[1] + Math.sqrt(0.5)*r; y = c[2] - Math.sqrt(0.5)*r; break;
            case 'urt':
                x = c[1] + Math.sqrt(0.5)*r; y = c[2] + Math.sqrt(0.5)*r; break;
            case 'top':
                x = c[1]; y = c[2] + r; break;
            case 'bot':
                x = c[1]; y = c[2] - r; break;
            case 'ulft':
            default:
                x = c[1] - Math.sqrt(0.5)*r; y = c[2] + Math.sqrt(0.5)*r; break;
        }
        return  new JXG.Coords(JXG.COORDS_BY_USER, [x, y], this.board);
    },


    // documented in geometry element
    cloneToBackground: function () {
        var copy = {}, r, er;
        copy.id = this.id + 'T' + this.numTraces;
        copy.elementClass = JXG.OBJECT_CLASS_CIRCLE;
        this.numTraces++;
        copy.center = {};
        copy.center.coords = this.center.coords;
        r = this.Radius();
        copy.Radius = function () { return r; };
        copy.getRadius = function () { return r; }; // deprecated

        copy.board = this.board;

        copy.visProp = JXG.deepCopy(this.visProp, this.visProp.traceattributes, true);
        copy.visProp.layer = this.board.options.layer.trace;
        JXG.clearVisPropOld(copy);

        er = this.board.renderer.enhancedRendering;
        this.board.renderer.enhancedRendering = true;
        this.board.renderer.drawEllipse(copy);
        this.board.renderer.enhancedRendering = er;
        this.traces[copy.id] = copy.rendNode;

        return this;
    },

    /**
     * Add transformations to this circle.
     * @param {JXG.Transform|Array} transform Either one {@link JXG.Transform} or an array of {@link JXG.Transform}s.
     * @returns {JXG.Circle} Reference to this circle object.
     */
    addTransform: function (transform) {
        var i,
            list = JXG.isArray(transform) ? transform : [transform],
            len = list.length;

        for (i = 0; i < len; i++) {
            this.center.transformations.push(list[i]);
            if (this.method === 'twoPoints') {
                this.point2.transformations.push(list[i]);
            }
        }
        
        return this;
    },

    // see geometryelement.js
    snapToGrid: function () {
        if (this.visProp.snaptogrid) {
            this.center.snapToGrid();

            if (this.method === 'twoPoints') {
                this.point2.snapToGrid();
            }
        }
        
        return this;
    },

    /**
     * TODO description
     * @param method TODO
     * @param coords TODO
     * @private
     */
    setPosition: function (method, coords) {
        var t;

        coords = new JXG.Coords(method, coords, this.board);
        t = this.board.create('transform', coords.usrCoords.slice(1), {type:'translate'});
        this.addTransform(t);

        return this;
    },

    /**
     * Sets x and y coordinate and calls the circle's update() method.
     * @param {number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinate in screen/user units
     * @param {Array} oldcoords previous coordinate in screen/user units
     * @returns {JXG.Circle} Reference to this circle.
     */
    setPositionDirectly: function (method, coords, oldcoords) {
        coords = new JXG.Coords(method, coords, this.board);
        oldcoords = new JXG.Coords(method, oldcoords, this.board);

        var diffc = JXG.Math.Statistics.subtract(coords.usrCoords, oldcoords.usrCoords),
            len = this.parents.length, i, p;

        for (i = 0; i < len; i++) {
            if (!JXG.getRef(this.board, this.parents[i]).draggable()) {
                return this;
            }
        }
        
        for (i = 0; i < len; i++) {
            p = JXG.getRef(this.board, this.parents[i]);
            p.coords.setCoordinates(JXG.COORDS_BY_USER, JXG.Math.Statistics.add(p.coords.usrCoords, diffc));
        }
        
        this.update();
        return this;
    },
    
    /**
     * Treats the circle as parametric curve and calculates its X coordinate.
     * @param {Number} t Number between 0 and 1.
     * @returns {Number} <tt>X(t)= radius*cos(t)+centerX</tt>.
     */
    X: function (t) {
        return this.Radius()*Math.cos(t*2.0*Math.PI)+this.center.coords.usrCoords[1];
    },

    /**
     * Treats the circle as parametric curve and calculates its Y coordinate.
     * @param {Number} t Number between 0 and 1.
     * @returns {Number} <tt>X(t)= radius*sin(t)+centerY</tt>.
     */
    Y: function (t) {
        return this.Radius()*Math.sin(t*2.0*Math.PI)+this.center.coords.usrCoords[2];
    },

    /**
     * Treat the circle as parametric curve and calculates its Z coordinate.
     * @param {Number} t ignored
     * @return {Number} 1.0
     */
    Z: function (t) {
        return 1.0;
    },

    /**
     * TODO description
     * @private
     */
    minX: function () {
        return 0.0;
    },

    /**
     * TODO description
     * @private
     */
    maxX: function () {
        return 1.0;
    },

    Area: function () {
        var r = this.Radius();
        return r*r*Math.PI;
    },

    bounds: function () {
        var uc = this.center.coords.usrCoords,
            r = this.Radius();

        return [uc[1] - r, uc[2] + r, uc[1] + r, uc[2] - r];
    }
});

/**
 * @class This element is used to provide a constructor for a circle. 
 * @pseudo
 * @description  A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius.
 * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function,
 * line, or circle). 
 * @name Circle
 * @augments JXG.Circle
 * @constructor
 * @type JXG.Circle
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, but the radius can be given
 * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the
 * line will determine the radius), or another {@link JXG.Circle}.
 * @example
 * // Create a circle providing two points
 * var p1 = board.create('point', [2.0, 2.0]);
 * var p2 = board.create('point', [2.0, 0.0]);
 * var c1 = board.create('circle', [p1, p2]);
 * 
 * // Create another circle using the above circle
 * var p3 = board.create('point', [3.0, 2.0]);
 * var c2 = board.create('circle', [p3, c1]);
 * </pre><div id="5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var cex1_board = JXG.JSXGraph.initBoard('5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var cex1_p1 = cex1_board.create('point', [2.0, 2.0]);
 *   var cex1_p2 = cex1_board.create('point', [2.0, 0.0]);
 *   var cex1_c1 = cex1_board.create('circle', [cex1_p1, cex1_p2]);
 *   var cex1_p3 = cex1_board.create('point', [3.0, 2.0]);
 *   var cex1_c2 = cex1_board.create('circle', [cex1_p3, cex1_c1]);
 * </script><pre>
 */
JXG.createCircle = function (board, parents, attributes) {
    var el, p, i, attr, isDraggable = true;

    p = [];
    for (i=0;i<parents.length;i++) {
        if (JXG.isPoint(parents[i])) {
            p[i] = parents[i];              // Point
        } else if (JXG.isArray(parents[i]) && parents[i].length>1) {
            attr = JXG.copyAttributes(attributes, board.options, 'circle', 'center');
            p[i] = board.create('point', parents[i], attr);  // Coordinates
        } else {
            p[i] = parents[i];              // Something else (number, function, string)
        }
    }
    
    attr = JXG.copyAttributes(attributes, board.options, 'circle');
   
    if( parents.length==2 && JXG.isPoint(p[0]) && JXG.isPoint(p[1]) ) {
        // Point/Point
        el = new JXG.Circle(board, 'twoPoints', p[0], p[1], attr);
    } else if( ( JXG.isNumber(p[0]) || JXG.isFunction(p[0]) || JXG.isString(p[0])) && JXG.isPoint(p[1]) ) {
        // Number/Point
        el = new JXG.Circle(board, 'pointRadius', p[1], p[0], attr);
    } else if( ( JXG.isNumber(p[1]) || JXG.isFunction(p[1]) || JXG.isString(p[1])) && JXG.isPoint(p[0]) ) {
        // Point/Number
        el = new JXG.Circle(board, 'pointRadius', p[0], p[1], attr);
    } else if( (p[0].elementClass == JXG.OBJECT_CLASS_CIRCLE) && JXG.isPoint(p[1]) ) {
        // Circle/Point
        el = new JXG.Circle(board, 'pointCircle', p[1], p[0], attr);
    } else if( (p[1].elementClass == JXG.OBJECT_CLASS_CIRCLE) && JXG.isPoint(p[0])) {
        // Point/Circle
        el = new JXG.Circle(board, 'pointCircle', p[0], p[1], attr);
    } else if( (p[0].elementClass == JXG.OBJECT_CLASS_LINE) && JXG.isPoint(p[1])) {
        // Line/Point
        el = new JXG.Circle(board, 'pointLine', p[1], p[0], attr);
    } else if( (p[1].elementClass == JXG.OBJECT_CLASS_LINE) && JXG.isPoint(p[0])) {
        // Point/Line
        el = new JXG.Circle(board, 'pointLine', p[0], p[1], attr);
    } else if( parents.length==3 && JXG.isPoint(p[0]) && JXG.isPoint(p[1]) && JXG.isPoint(p[2])) {
        // Circle through three points
        el = JXG.createCircumcircle(board, p, attributes);
        //el.center.setProperty({visible:false});
        //isDraggable = false;
    } else
        throw new Error("JSXGraph: Can't create circle with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,point], [point,number], [point,function], [point,circle], [point,point,point]");
    
    el.isDraggable = isDraggable;

    el.parents = [];
    for (i = 0; i < parents.length; i++) {
        if (parents[i].id) {
            el.parents.push(parents[i].id);
        }
    }
    
    el.elType = 'circle';
    return el;
};

JXG.JSXGraph.registerElement('circle', JXG.createCircle);


/*
    Copyright 2010
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
*/    

/**
 * @fileoverview In this file the conic sections defined.
 */

/**
 * @class This element is used to provide a constructor for an ellipse. An ellipse is given by two points (the foci) and a third point on the the ellipse or 
 * the length of the major axis.
 * @pseudo
 * @description
 * @name Ellipse
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of
 * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.
 * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of
 * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis
 * Optional parameters four and five are numbers which define the curve length (e.g. start/end). Default values are -pi and pi.
 * @example
 * // Create an Ellipse by three points
 * var A = board.create('point', [-1,4]);
 * var B = board.create('point', [-1,-4]);
 * var C = board.create('point', [1,1]);
 * var el = board.create('ellipse',[A,B,C]);
 * </pre><div id="a4d7fb6f-8708-4e45-87f2-2379ae2bd2c0" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var glex1_board = JXG.JSXGraph.initBoard('a4d7fb6f-8708-4e45-87f2-2379ae2bd2c0', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});
 *   var A = glex1_board.create('point', [-1,4]);
 *   var B = glex1_board.create('point', [-1,-4]);
 *   var C = glex1_board.create('point', [1,1]);
 *   var el = glex1_board.create('ellipse',[A,B,C]);
 * </script><pre>
 */
JXG.createEllipse = function(board, parents, attributes) {
    var F = [],  // focus 1 and focus 2
        C, majorAxis, i,
        rotationMatrix,
        attr_foci = JXG.copyAttributes(attributes, board.options, 'conic', 'foci'),
        attr_curve = JXG.copyAttributes(attributes, board.options, 'conic');

    // The foci and the third point are either points or coordinate arrays.
    for (i = 0; i < 2; i++) {
        if (parents[i].length > 1) { // focus i given by coordinates
            F[i] = board.create('point', parents[i], attr_foci);
        } else if (JXG.isPoint(parents[i])) { // focus i given by point
            F[i] = JXG.getReference(board,parents[i]);
        } else if ((typeof parents[i] == 'function') && (parents[i]().elementClass === JXG.OBJECT_CLASS_POINT)) {  // given by function
            F[i] = parents[i]();
        } else if (JXG.isString(parents[i])) { // focus i given by point name
            F[i] = JXG.getReference(board,parents[i]);
        } else
            throw new Error("JSXGraph: Can't create Ellipse with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                            "\nPossible parent types: [point,point,point], [point,point,number|function]");
    }
    
    if (JXG.isNumber(parents[2])) { // length of major axis
        majorAxis = JXG.createFunction(parents[2],board);
    } else if ((typeof parents[2] == 'function') && (JXG.isNumber(parents[2]()))){
        majorAxis = parents[2];
    } else {
        if (JXG.isPoint(parents[2])) {                                               // point on ellipse
            C = JXG.getReference(board,parents[2]);
        } else if (parents[2].length>1) {                                            // point on ellipse given by coordinates
            C = board.create('point', parents[2], attr_foci);
        } else if ((typeof parents[2] == 'function') && (parents[2]().elementClass == JXG.OBJECT_CLASS_POINT)) {  // given by function
            C = parents[2]();
        } else if (JXG.isString(parents[2])) {                                      // focus i given by point name
            C = JXG.getReference(board,parents[2]);
        } else {
            throw new Error("JSXGraph: Can't create Ellipse with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) +"'." +
                            "\nPossible parent types: [point,point,point], [point,point,number|function]");
        }
        majorAxis = function(){ return C.Dist(F[0])+C.Dist(F[1]);};
    }

    if (typeof parents[4]=='undefined') parents[4] = 1.0001*Math.PI;   // to
    if (typeof parents[3]=='undefined') parents[3] = -1.0001*Math.PI;  // from

    var M = board.create('point', [
                function(){return (F[0].X()+F[1].X())*0.5;},
                function(){return (F[0].Y()+F[1].Y())*0.5;}
            ], attr_foci);

    var transformFunc = function() {
            var ax = F[0].X(),
                ay = F[0].Y(),
                bx = F[1].X(),
                by = F[1].Y(),
                beta, co, si;

            // Rotate by the slope of the line [F[0],F[1]]
            var sgn = (bx-ax>0)?1:-1;
            if (Math.abs(bx-ax)>0.0000001) {
                beta = Math.atan2(by-ay,bx-ax)+ ((sgn<0)?Math.PI:0);
            } else {
                beta = ((by-ay>0)?0.5:-0.5)*Math.PI;
            }
            co = Math.cos(beta);
            si = Math.sin(beta);
            var m = [
                        [1,     0,  0],
                        [M.X(),co,-si],
                        [M.Y(),si, co]
                    ];
            return m;
        };

    var curve = board.create('curve', [
            function(x) {return 0;}, 
            function(x) {return 0;}, 
            parents[3], 
            parents[4]], attr_curve);

    var polarForm = function(phi,suspendUpdate) {
                var a = majorAxis()*0.5,
                    aa = a*a,
                    e = F[1].Dist(F[0])*0.5,
                    bb = aa-e*e,
                    b = Math.sqrt(bb), 
                    transformMat = [[1,0,0],[0,1,0],[0,0,1]],
                    mx, my;
                    
                if (!suspendUpdate) {
                    rotationMatrix = transformFunc();
                    mx = M.X();
                    my = M.Y();
                    transformMat[0][0] = rotationMatrix[0][0];
                    transformMat[0][1] = 0.0;
                    transformMat[0][2] = 0.0;
                    transformMat[1][0] = mx*(1-rotationMatrix[1][1])+my*rotationMatrix[1][2];
                    transformMat[1][1] = rotationMatrix[1][1];
                    transformMat[1][2] = rotationMatrix[2][1];
                    transformMat[2][0] = my*(1-rotationMatrix[1][1])-mx*rotationMatrix[1][2];
                    transformMat[2][1] = rotationMatrix[1][2];
                    transformMat[2][2] = rotationMatrix[2][2];
                    curve.quadraticform = 
                        JXG.Math.matMatMult(JXG.Math.transpose(transformMat),
                        JXG.Math.matMatMult(
                            [
                                [-1+mx*mx/(a*a)+my*my/bb, -mx/aa , -mx/bb],
                                [-mx/aa                 ,   1/aa ,  0    ],
                                [-my/bb                 ,      0 ,  1/bb ]
                            ],
                        transformMat)); 
                }
                return JXG.Math.matVecMult(rotationMatrix,[1,a*Math.cos(phi),b*Math.sin(phi)]);
        };

    curve.X = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[1];};
    curve.Y = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[2];};
    curve.midpoint = M;
    curve.type = JXG.OBJECT_TYPE_CONIC;

    M.addChild(curve);
    for (i=0; i<2; i++) {
        if (JXG.isPoint(F[i])) {
            F[i].addChild(curve);
        }
    }
    if (JXG.isPoint(C)) {
        C.addChild(curve);
    }
    curve.parents = [];
    for (i=0; i < parents.length; i++) {
        if (parents[i].id) {
            curve.parents.push(parents[i].id);
        }
    }
    
    return curve;
};

/**
 * @class This element is used to provide a constructor for an hyperbola. An hyperbola is given by two points (the foci) and a third point on the the hyperbola or 
 * the length of the major axis.
 * @pseudo
 * @description
 * @name Hyperbola
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of
 * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.
 * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of
 * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis
 * Optional parameters four and five are numbers which define the curve length (e.g. start/end). Default values are -pi and pi.
 * @example
 * // Create an Hyperbola by three points
 * var A = board.create('point', [-1,4]);
 * var B = board.create('point', [-1,-4]);
 * var C = board.create('point', [1,1]);
 * var el = board.create('hyperbola',[A,B,C]);
 * </pre><div id="cf99049d-a3fe-407f-b936-27d76550f8c4" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var glex1_board = JXG.JSXGraph.initBoard('cf99049d-a3fe-407f-b936-27d76550f8c4', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});
 *   var A = glex1_board.create('point', [-1,4]);
 *   var B = glex1_board.create('point', [-1,-4]);
 *   var C = glex1_board.create('point', [1,1]);
 *   var el = glex1_board.create('hyperbola',[A,B,C]);
 * </script><pre>
 */
JXG.createHyperbola = function(board, parents, attributes) {
    var F = [],  // focus 1 and focus 2
        C, 
        majorAxis,
        i,
        rotationMatrix,
        attr_foci = JXG.copyAttributes(attributes, board.options, 'conic', 'foci'),
        attr_curve = JXG.copyAttributes(attributes, board.options, 'conic');

    // The foci and the third point are either points or coordinate arrays.
    for (i=0;i<2;i++) {
        if (parents[i].length>1) { // focus i given by coordinates
            F[i] = board.create('point', parents[i], attr_focu);
        } else if (JXG.isPoint(parents[i])) { // focus i given by point
            F[i] = JXG.getReference(board,parents[i]);
        } else if ((typeof parents[i] == 'function') && (parents[i]().elementClass == JXG.OBJECT_CLASS_POINT)) {  // given by function
            F[i] = parents[i]();
        } else if (JXG.isString(parents[i])) { // focus i given by point name
            F[i] = JXG.getReference(board,parents[i]);
        } else
            throw new Error("JSXGraph: Can't create Hyperbola with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                            "\nPossible parent types: [point,point,point], [point,point,number|function]");
    }
    if (JXG.isNumber(parents[2])) { // length of major axis
        majorAxis = JXG.createFunction(parents[2],board);
    } else if ((typeof parents[2] == 'function') && (JXG.isNumber(parents[2]()))){
        majorAxis = parents[2];
    } else {
        if (JXG.isPoint(parents[2])) {                                               // point on ellipse
            C = JXG.getReference(board,parents[2]);
        } else if (parents[2].length>1) {                                            // point on ellipse given by coordinates
            C = board.create('point', parents[2], attr_foci);
        } else if ((typeof parents[2] == 'function') && (parents[2]().elementClass == JXG.OBJECT_CLASS_POINT)) {  // given by function
            C = parents[2]();
        } else if (JXG.isString(parents[2])) {                                      // focus i given by point name
            C = JXG.getReference(board,parents[2]);
        } else {
            throw new Error("JSXGraph: Can't create Hyperbola with parent types '" + 
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) +"'." +
                            "\nPossible parent types: [point,point,point], [point,point,number|function]");
        }
        majorAxis = function(){ return C.Dist(F[0])-C.Dist(F[1]);};
    }

    if (typeof parents[4]=='undefined') parents[4] = 1.0001*Math.PI;   // to
    if (typeof parents[3]=='undefined') parents[3] = -1.0001*Math.PI;  // from

    var M = board.create('point', [
                function(){return (F[0].X()+F[1].X())*0.5;},
                function(){return (F[0].Y()+F[1].Y())*0.5;}
            ], attr_foci);

    var transformFunc = function() {
            var ax = F[0].X(),
                ay = F[0].Y(),
                bx = F[1].X(),
                by = F[1].Y(),
                beta;

            // Rotate by the slope of the line [F[0],F[1]]
            var sgn = (bx-ax>0)?1:-1;
            if (Math.abs(bx-ax)>0.0000001) {
                beta = Math.atan2(by-ay,bx-ax)+ ((sgn<0)?Math.PI:0);
            } else {
                beta = ((by-ay>0)?0.5:-0.5)*Math.PI;
            }
            var m = [
                        [1,    0,             0],
                        [M.X(),Math.cos(beta),-Math.sin(beta)],
                        [M.Y(),Math.sin(beta), Math.cos(beta)]
                    ];
            return m;
        };

    var curve = board.create('curve',[function(x) {return 0;},function(x) {return 0;},parents[3],parents[4]], attr_curve);
    /*
    * Hyperbola is defined by (a*sec(t),b*tan(t)) and sec(t) = 1/cos(t)
    */
    var polarForm = function(phi,suspendUpdate) {
                var a = majorAxis()*0.5,
                    aa = a*a,
                    e = F[1].Dist(F[0])*0.5,
                    b = Math.sqrt(-a*a+e*e), 
                    bb = b*b,
                    transformMat = [[1,0,0],[0,1,0],[0,0,1]],
                    mx, my;
                    
                if (!suspendUpdate) {
                    rotationMatrix = transformFunc();
                    mx = M.X();
                    my = M.Y();
                    transformMat[0][0] = rotationMatrix[0][0];
                    transformMat[0][1] = 0.0;
                    transformMat[0][2] = 0.0;
                    transformMat[1][0] = mx*(1-rotationMatrix[1][1])+my*rotationMatrix[1][2];
                    transformMat[1][1] = rotationMatrix[1][1];
                    transformMat[1][2] = rotationMatrix[2][1];
                    transformMat[2][0] = my*(1-rotationMatrix[1][1])-mx*rotationMatrix[1][2];
                    transformMat[2][1] = rotationMatrix[1][2];
                    transformMat[2][2] = rotationMatrix[2][2];
                    curve.quadraticform = 
                        JXG.Math.matMatMult(JXG.Math.transpose(transformMat),
                        JXG.Math.matMatMult(
                            [
                                [-1+mx*mx/aa+my*my/bb, -mx/aa , my/bb],
                                [-mx/aa              ,    1/aa,  0   ],
                                [my/bb               ,      0 , -1/bb]
                            ],
                        transformMat)); 
                }
                return JXG.Math.matVecMult(rotationMatrix,[1,a/Math.cos(phi),b*Math.tan(phi)]);
        };

    curve.X = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[1];};
    curve.Y = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[2];};
    curve.midpoint = M;
    curve.type = JXG.OBJECT_TYPE_CONIC;
    
    M.addChild(curve);
    for (i=0; i<2; i++) {
        if (JXG.isPoint(F[i])) {
            F[i].addChild(curve);
        }
    }
    if (JXG.isPoint(C)) {
        C.addChild(curve);
    }
    curve.parents = [];
    for (i=0; i < parents.length; i++) {
        if (parents[i].id) {
            curve.parents.push(parents[i].id);
        }
    }
    
    return curve;
};

/**
 * @class This element is used to provide a constructor for a parabola. A parabola is given by one point (the focus) and a line (the directrix).
 * @pseudo
 * @description
 * @name Parabola
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array_JXG.Line} point,line Parent elements are a point and a line.
 * Optional parameters three and four are numbers which define the curve length (e.g. start/end). Default values are -pi and pi.
 * @example
 * // Create a parabola by a point C and a line l.
 * var A = board.create('point', [-1,4]);
 * var B = board.create('point', [-1,-4]);
 * var l = board.create('line', [A,B]);
 * var C = board.create('point', [1,1]);
 * var el = board.create('parabola',[C,l]);
 * </pre><div id="524d1aae-217d-44d4-ac58-a19c7ab1de36" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var glex1_board = JXG.JSXGraph.initBoard('524d1aae-217d-44d4-ac58-a19c7ab1de36', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});
 *   var A = glex1_board.create('point', [-1,4]);
 *   var B = glex1_board.create('point', [-1,-4]);
 *   var l = glex1_board.create('line', [A,B]);
 *   var C = glex1_board.create('point', [1,1]);
 *   var el = glex1_board.create('parabola',[C,l]);
 * </script><pre>
 */
JXG.createParabola = function(board, parents, attributes) {
    var F1 = parents[0], // focus
        l = parents[1],  // directrix
        rotationMatrix,
        attr_foci = JXG.copyAttributes(attributes, board.options, 'conic', 'foci'),
        attr_curve = JXG.copyAttributes(attributes, board.options, 'conic');

    if (parents[0].length>1) { // focus 1 given by coordinates
        F1 = board.create('point', parents[0], attr_foci);
    } else if (JXG.isPoint(parents[0])) { // focus i given by point
        F1 = JXG.getReference(board,parents[0]);
    } else if ((typeof parents[0] == 'function') && (parents[0]().elementClass == JXG.OBJECT_CLASS_POINT)) {  // given by function
        F1 = parents[0]();
    } else if (JXG.isString(parents[0])) { // focus i given by point name
        F1 = JXG.getReference(board,parents[0]);
    } else
        throw new Error("JSXGraph: Can't create Parabola with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,line]");

    if (typeof parents[3]=='undefined') parents[3] = 10.0;   // to
    if (typeof parents[2]=='undefined') parents[2] = -10.0;  // from

    var M = board.create('point', [
                function() {
                    var v = [0,l.stdform[1],l.stdform[2]];
                    v = JXG.Math.crossProduct(v,F1.coords.usrCoords);
                    return JXG.Math.Geometry.meetLineLine(v,l.stdform,0,board).usrCoords;
                }
            ], attr_foci);

    var transformFunc = function() {
            var beta = Math.atan(l.getSlope()),                
                x = (M.X()+F1.X())*0.5,
                y = (M.Y()+F1.Y())*0.5;
            beta += (F1.Y()-M.Y()<0 || (F1.Y()==M.Y() && F1.X()>M.X()) ) ? Math.PI : 0;

            // Rotate by the slope of the line l (Leitlinie = directrix)
            var m = [
                        [1,    0,             0],
                        [x*(1-Math.cos(beta))+y*Math.sin(beta),Math.cos(beta),-Math.sin(beta)],
                        [y*(1-Math.cos(beta))-x*Math.sin(beta),Math.sin(beta), Math.cos(beta)]
                    ];
            return m;
        };

    var curve = board.create('curve',[function(x) {return 0;},function(x) {return 0;},parents[2],parents[3]], attr_curve);

    var polarForm = function(t,suspendUpdate) {
                var e = M.Dist(F1)*0.5,
                    transformMat = [[1,0,0],[0,1,0],[0,0,1]],
                    a = (M.X()+F1.X())*0.5, 
                    b = (M.Y()+F1.Y())*0.5;
                
                if (!suspendUpdate) {
                    rotationMatrix = transformFunc();
                    transformMat[0][0] = rotationMatrix[0][0];
                    transformMat[0][1] = 0.0;
                    transformMat[0][2] = 0.0;
                    transformMat[1][0] = a*(1-rotationMatrix[1][1])+b*rotationMatrix[1][2];
                    transformMat[1][1] = rotationMatrix[1][1];
                    transformMat[1][2] = rotationMatrix[2][1];
                    transformMat[2][0] = b*(1-rotationMatrix[1][1])-a*rotationMatrix[1][2];
                    transformMat[2][1] = rotationMatrix[1][2];
                    transformMat[2][2] = rotationMatrix[2][2];
                    curve.quadraticform = 
                        JXG.Math.matMatMult(JXG.Math.transpose(transformMat),
                        JXG.Math.matMatMult(
                            [
                                [-b*4*e-a*a, a, 2*e],
                                [a,       -1, 0],
                                [2*e,      0, 0]
                            ],
                        transformMat)); 
                }
                return JXG.Math.matVecMult(rotationMatrix,[1,t+a,t*t/(e*4)+b]);
        };
    curve.X = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[1];};
    curve.Y = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[2];};
    curve.type = JXG.OBJECT_TYPE_CONIC;
    
    M.addChild(curve);
    if (JXG.isPoint(F[1])) {
        F[1].addChild(curve);
    }
    l.addChild(curve);
    curve.parents = [];
    for (i=0; i < parents.length; i++) {
        if (parents[i].id) {
            curve.parents.push(parents[i].id);
        }
    }
    
    return curve;
};

/**
 * 
 * @class This element is used to provide a constructor for a generic conic section uniquely defined by five points.
 * @pseudo
 * @description
 * @name Conic
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Conic
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array_JXG.Point,array_JXG.Point,array_} point,point,point,point,point Parent elements are five points.
 * @param {number_number_number_number_number_number} 6 numbers (a_00,a_11,a_22,a_01,a_12,a_22)
 * @example
 * // Create a conic section through the points A, B, C, D, and E.
 *  var A = board.create('point', [1,5]);
 *  var B = board.create('point', [1,2]);
 *  var C = board.create('point', [2,0]);
 *  var D = board.create('point', [0,0]);
 *  var E = board.create('point', [-1,5]);
 *  var conic = board.create('conic',[A,B,C,D,E]);
 * </pre><div id="2d79bd6a-db9b-423c-9cba-2497f0b06320" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var glex1_board = JXG.JSXGraph.initBoard('2d79bd6a-db9b-423c-9cba-2497f0b06320', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});
 *   var A = glex1_board.create('point', [1,5]);
 *   var B = glex1_board.create('point', [1,2]);
 *   var C = glex1_board.create('point', [2,0]);
 *   var D = glex1_board.create('point', [0,0]);
 *   var E = glex1_board.create('point', [-1,5]);
 *   var conic = glex1_board.create('conic',[A,B,C,D,E]);
 * </script><pre>
 */
JXG.createConic = function(board, parents, attributes) {
    var rotationMatrix = [[1,0,0],[0,1,0],[0,0,1]], 
        eigen, a, b, c, M = [[1,0,0],[0,1,0],[0,0,1]],
        c1, c2, points = [], i, definingMat, 
        givenByPoints, 
        p = [],
        attr_foci = JXG.copyAttributes(attributes, board.options, 'conic', 'foci'),
        attr_curve = JXG.copyAttributes(attributes, board.options, 'conic');

    if (parents.length==5) {
        givenByPoints = true;
    } else if (parents.length==6) {
        givenByPoints = false;
    } else 
        throw new Error("JSXGraph: Can't create generic Conic with " + parent.length + " parameters.");  

    if (givenByPoints) {
        for (i=0;i<5;i++) {
            if (parents[i].length>1) { // point i given by coordinates
                points[i] = board.create('point', parents[i], attr_foci);
            } else if (JXG.isPoint(parents[i])) { // point i given by point
                points[i] = JXG.getReference(board,parents[i]);
            } else if ((typeof parents[i] == 'function') && (parents[i]().elementClass == JXG.OBJECT_CLASS_POINT)) {  // given by function
                points[i] = parents[i]();
            } else if (JXG.isString(parents[i])) { // point i given by point name
                points[i] = JXG.getReference(board,parents[i]);
            } else
                throw new Error("JSXGraph: Can't create Conic section with parent types '" + (typeof parents[i]) + "'." +
                                "\nPossible parent types: [point,point,point,point,point], [a00,a11,a22,a01,a02,a12]");
        }
    } else {
        /* Usual notation (x,y,z):
         *  [[A0,A3,A4],
         *   [A3,A1,A5],
         *   [A4,A5,A2]]. 
         * Our notation (z,x,y): 
         *  [[-A2   , A4*2.0, A5*0.5],
         *   [A4*2.0,    -A0, A3*0.5],
         *   [A5*0.5, A3*0.5,    -A1]] 
         * New: (z,x,y): 
         *  [[A2, A4, A5],
         *   [A4, A0, A3],
         *   [A5, A3, A1]] 
        */
        definingMat = [[0,0,0],[0,0,0],[0,0,0]];
        definingMat[0][0] = (JXG.isFunction(parents[2])) ? function(){ return    parents[2]();} : function(){ return    parents[2];};
        definingMat[0][1] = (JXG.isFunction(parents[4])) ? function(){ return    parents[4]();} : function(){ return    parents[4];};
        definingMat[0][2] = (JXG.isFunction(parents[5])) ? function(){ return    parents[5]();} : function(){ return    parents[5];};
        definingMat[1][1] = (JXG.isFunction(parents[0])) ? function(){ return    parents[0]();} : function(){ return    parents[0];};
        definingMat[1][2] = (JXG.isFunction(parents[3])) ? function(){ return    parents[3]();} : function(){ return    parents[3];};
        definingMat[2][2] = (JXG.isFunction(parents[1])) ? function(){ return    parents[1]();} : function(){ return    parents[1];};
    }

    // sym(A) = A + A^t . Manipulates A in place.
    var sym = function(A) {
        var i, j;
        for (i=0;i<3;i++) {
            for (j=i;j<3;j++) {
                A[i][j] += A[j][i];
            }
        }
        for (i=0;i<3;i++) {
            for (j=0;j<i;j++) {
                A[i][j] = A[j][i];
            }
        }
        return A;
    };

    // degconic(v,w) = sym(v*w^t)
    var degconic = function(v,w) {
        var i, j, mat = [[0,0,0],[0,0,0],[0,0,0]];
        for (i=0;i<3;i++) {
            for (j=0;j<3;j++) {
                mat[i][j] = v[i]*w[j];
            }
        }
        return sym(mat);
    };

    // (p^t*B*p)*A-(p^t*A*p)*B
    var fitConic = function(A,B,p)  {
        var pBp, pAp, Mv, mat = [[0,0,0],[0,0,0],[0,0,0]], i, j;
        Mv = JXG.Math.matVecMult(B,p);
        pBp = JXG.Math.innerProduct(p,Mv);
        Mv = JXG.Math.matVecMult(A,p);
        pAp = JXG.Math.innerProduct(p,Mv);
        for (i=0;i<3;i++) {
            for (j=0;j<3;j++) {
                mat[i][j] = pBp*A[i][j]-pAp*B[i][j];
            }
        }
        return mat;
    };
 
    // Here, the defining functions for the curve are just dummy functions.
    // In polarForm there is a reference to curve.quadraticform.
    var curve = board.create('curve',[function(x) {return 0;},function(x) {return 0;},0,2*Math.PI], attr_curve);

    var polarForm = function(phi,suspendUpdate) {
        var i, j, len, v;
        if (!suspendUpdate) {
            if (givenByPoints) {
                // Copy the point coordinate vectors
                for (i=0;i<5;i++) { 
                    p[i] = points[i].coords.usrCoords; 
                }
                // Compute the quadratic form
                c1 = degconic(JXG.Math.crossProduct(p[0],p[1]),JXG.Math.crossProduct(p[2],p[3]));
                c2 = degconic(JXG.Math.crossProduct(p[0],p[2]),JXG.Math.crossProduct(p[1],p[3]));
                M = fitConic(c1,c2,p[4]);
            } else {
                for (i=0;i<3;i++) {
                    for (j=i;j<3;j++) {
                        M[i][j] = definingMat[i][j]();
                        if (j>i) M[j][i] = M[i][j];     
                    }
                }
            }
            curve.quadraticform = M;    // Here is the reference back to the curve.
            
            // Compute Eigenvalues and Eigenvectors
            eigen = JXG.Math.Numerics.Jacobi(M);
            // Scale the Eigenvalues such that the first Eigenvalue is positive
            if (eigen[0][0][0]<0) {
                eigen[0][0][0] *= (-1);
                eigen[0][1][1] *= (-1);
                eigen[0][2][2] *= (-1);
            }
            // Normalize the Eigenvectors
            for (i=0;i<3;i++) {
                len = 0.0;
                for (j=0;j<3;j++) {
                    len += eigen[1][j][i]*eigen[1][j][i];
                }
                len = Math.sqrt(len);
                for (j=0;j<3;j++) {
                    //eigen[1][j][i] /= len;
                }
            }
            rotationMatrix = eigen[1];
            c = Math.sqrt(Math.abs(eigen[0][0][0]));
            a = Math.sqrt(Math.abs(eigen[0][1][1]));
            b = Math.sqrt(Math.abs(eigen[0][2][2]));

        }
        // The degenerate cases with eigen[0][i][i]==0 are not handled correct yet.
        if (eigen[0][1][1]<=0.0 && eigen[0][2][2]<=0.0) {
            v = JXG.Math.matVecMult(rotationMatrix,[1/c,Math.cos(phi)/a,Math.sin(phi)/b]);
        } else if (eigen[0][1][1]<=0.0 && eigen[0][2][2]>0.0) {
            v = JXG.Math.matVecMult(rotationMatrix,[Math.cos(phi)/c,1/a,Math.sin(phi)/b]);
        } else if (eigen[0][2][2]<0.0) {
            v = JXG.Math.matVecMult(rotationMatrix,[Math.sin(phi)/c,Math.cos(phi)/a,1/b]);
        } 
        // Normalize
        v[1] /= v[0];
        v[2] /= v[0];
        v[0] = 1.0;
        return v;
    };

    curve.X = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[1];};
    curve.Y = function(phi,suspendUpdate) {return polarForm(phi,suspendUpdate)[2];};

    // Center coordinates see http://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections
    curve.midpoint = board.create('point',
        [
        function(){ 
            var m = curve.quadraticform;
            return [
                m[1][1]*m[2][2]-m[1][2]*m[1][2],
                m[1][2]*m[0][2]-m[2][2]*m[0][1],
                m[0][1]*m[1][2]-m[1][1]*m[0][2]
            ];
        }
        ], attr_foci);

    curve.type = JXG.OBJECT_TYPE_CONIC;
    
    if (givenByPoints) {
        for (i=0;i<5;i++) {
            if(JXG.isPoint(points[i])) {
                points[i].addChild(curve);
            }
        }
        curve.parents = [];
        for (i=0; i<parents.length; i++) {
            if (parents[i].id) {
                curve.parents.push(parents[i].id);
            }
        }
    }
    curve.addChild(curve.midpoint);
    
    return curve;
};

JXG.JSXGraph.registerElement('ellipse', JXG.createEllipse);
JXG.JSXGraph.registerElement('hyperbola', JXG.createHyperbola);
JXG.JSXGraph.registerElement('parabola', JXG.createParabola);
JXG.JSXGraph.registerElement('conic', JXG.createConic);



/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * Creates a new instance of JXG.Polygon.
 * @class Polygon stores all style and functional properties that are required
 * to draw and to interactact with a polygon.
 * @param {JXG.Board} board Reference to the board the polygon is to be drawn on.
 * @param {Array} vertices Unique identifiers for the points defining the polygon.
 * Last point must be first point. Otherwise, the first point will be added at the list.
 * @param {Object} attributes An object which contains properties as given in {@link JXG.Options.elements}
 * and {@link JXG.Options.polygon}.
 * @constructor
 * @extends JXG.GeometryElement
 */

JXG.Polygon = function (board, vertices, attributes) {
    this.constructor(board, attributes, JXG.OBJECT_TYPE_POLYGON, JXG.OBJECT_CLASS_AREA);

    var i, vertex, l,
        attr_line = JXG.copyAttributes(attributes, board.options, 'polygon', 'borders');

    this.withLines = attributes.withlines;
    this.attr_line = attr_line;

    /**
     * References to the points defining the polygon. The last vertex is the same as the first vertex.
     * @type Array
     */
    this.vertices = [];
    for(i=0; i<vertices.length; i++) {
       vertex = JXG.getRef(this.board, vertices[i]);
       this.vertices[i] = vertex;
    }

    if(this.vertices[this.vertices.length-1] != this.vertices[0]) {
        this.vertices.push(this.vertices[0]);
    }

    /**
     * References to the border lines of the polygon.
     * @type Array
     */
    this.borders = [];
    if (this.withLines) {
        for(i = 0; i < this.vertices.length - 1; i++) {
            attr_line.id = attr_line.ids && attr_line.ids[i];
            attr_line.strokecolor = JXG.isArray(attr_line.colors) && attr_line.colors[i % attr_line.colors.length] || attr_line.strokecolor;
            if (attr_line.strokecolor===false) attr_line.strokecolor = 'none';
            l = JXG.createSegment(board, [this.vertices[i], this.vertices[i+1]], attr_line);
            l.dump = false;
            this.borders[i] = l;
            l.parentPolygon = this;
        }
    }

    // Add polygon as child to defining points
    for(i=0; i<this.vertices.length-1; i++) { // last vertex is first vertex
        vertex = JXG.getReference(this.board, this.vertices[i]);
        vertex.addChild(this);
    }


    /* Register polygon at board */
    this.id = this.board.setId(this, 'Py');
    this.board.renderer.drawPolygon(this);
    this.board.finalizeAdding(this);
    this.elType = 'polygon';

    // create label
    this.createLabel();

    this.methodMap.borders = 'borders';
    this.methodMap.vertices = 'vertices';

};
JXG.Polygon.prototype = new JXG.GeometryElement;


JXG.extend(JXG.Polygon.prototype, /** @lends JXG.Polygon.prototype */ {
    /**
     * Checks whether (x,y) is near the polygon.
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @return {Boolean} Returns true, if (x,y) is inside or at the boundary the polygon, otherwise false.
     */
    hasPoint: function (x,y) {

        var i, j, len, c = false;

        if (this.visProp.hasinnerpoints) {
            // All points of the polygon trigger hasPoint: inner and boundary points
            len = this.vertices.length;
            // See http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for a reference
            for (i=0, j=len-2; i<len-1; j=i++) { // last vertex is first vertex
                if (((this.vertices[i].coords.scrCoords[2] > y) != (this.vertices[j].coords.scrCoords[2] > y))
                    && (x < (this.vertices[j].coords.scrCoords[1] - this.vertices[i].coords.scrCoords[1]) * (y - this.vertices[i].coords.scrCoords[2])
                        / (this.vertices[j].coords.scrCoords[2] - this.vertices[i].coords.scrCoords[2]) + this.vertices[i].coords.scrCoords[1])) {
                    c = !c;
                }
            }
        } else {
            // Only boundary points trigger hasPoint
            len = this.borders.length;
            for (i=0; i<len; i++) {
                if (this.borders[i].hasPoint(x,y)) {
                    c = true;
                    break;
                }
            }
        }

        return c;
    },

    /**
     * Uses the boards renderer to update the polygon.
     */
    updateRenderer: function () {
        if (this.needsUpdate) {
            this.board.renderer.updatePolygon(this);
            this.needsUpdate = false;
        }
        if(this.hasLabel && this.label.content.visProp.visible) {
            //this.label.setCoordinates(this.coords);
            this.label.content.update();
            //this.board.renderer.updateLabel(this.label);
            this.board.renderer.updateText(this.label.content);
        }
    },

    /**
     * return TextAnchor
     */
    getTextAnchor: function() {
        var a = this.vertices[0].X(),
            b = this.vertices[0].Y(),
            x = a,
            y = b,
            i;

        for (i = 0; i < this.vertices.length; i++) {
            if (this.vertices[i].X() < a)
                a = this.vertices[i].X();
            if (this.vertices[i].X() > x)
                x = this.vertices[i].X();
            if (this.vertices[i].Y() > b)
                b = this.vertices[i].Y();
            if (this.vertices[i].Y() < y)
                y = this.vertices[i].Y();
        }

        return new JXG.Coords(JXG.COORDS_BY_USER, [(a + x)*0.5, (b + y)*0.5], this.board);
    },

    getLabelAnchor: JXG.shortcut(JXG.Polygon.prototype, 'getTextAnchor'),

    // documented in geometry element
    cloneToBackground: function() {
        var copy = {}, er;

        copy.id = this.id + 'T' + this.numTraces;
        this.numTraces++;
        copy.vertices = this.vertices;
        copy.visProp = JXG.deepCopy(this.visProp, this.visProp.traceattributes, true);
        copy.visProp.layer = this.board.options.layer.trace;
        copy.board = this.board;
        JXG.clearVisPropOld(copy);

        er = this.board.renderer.enhancedRendering;
        this.board.renderer.enhancedRendering = true;
        this.board.renderer.drawPolygon(copy);
        this.board.renderer.enhancedRendering = er;
        this.traces[copy.id] = copy.rendNode;

        return this;
    },

    /**
     * Hide the polygon including its border lines. It will still exist but not visible on the board.
     */
    hideElement: function() {
        var i;

        this.visProp.visible = false;
        this.board.renderer.hide(this);

        for(i = 0; i < this.borders.length; i++) {
            this.borders[i].hideElement();
        }

        if (this.hasLabel && JXG.exists(this.label)) {
            this.label.hiddenByParent = true;
            if(this.label.content.visProp.visible) {
                this.board.renderer.hide(this.label.content);
            }
        }
    },

    /**
     * Make the element visible.
     */
    showElement: function() {
        var i;

        this.visProp.visible = true;
        this.board.renderer.show(this);

        for(i = 0; i < this.borders.length; i++) {
            this.borders[i].showElement();
        }

        if (this.hasLabel && JXG.exists(this.label)) {
            if(this.label.content.visProp.visible) {
                this.board.renderer.show(this.label.content);
            }
        }
    },

    /**
     * returns the area of the polygon
     */
    Area: function() {
        //Surveyor's Formula
        var area = 0, i;

        for (i = 0; i < this.vertices.length - 1; i++) {
            area += (this.vertices[i].X()*this.vertices[i+1].Y()-this.vertices[i+1].X()*this.vertices[i].Y()); // last vertex is first vertex
        }
        area /= 2.0;
        return Math.abs(area);
    },

    /**
     * This method removes the SVG or VML nodes of the lines and the filled area from the renderer, to remove
     * the object completely you should use {@link JXG.Board#removeObject}.
     */
    remove: function () {
        var i;
        for (i = 0; i < this.borders.length; i++) {
            this.board.removeObject(this.borders[i]);
        }
        //this.board.renderer.remove(this.rendNode);
        JXG.GeometryElement.prototype.remove.call(this);
    },

    /**
     * Finds the index to a given point reference.
     * @param {JXG.Point} p Reference to an element of type {@link JXG.Point}
     */
    findPoint: function (p) {
        var i;

        if (!JXG.isPoint(p)) {
            return -1;
        }

        for (i = 0; i < this.vertices.length; i++) {
            if (this.vertices[i].id === p.id) {
                return i;
            }
        }

        return -1;
    },

    /**
     * Add more points to the polygon. The new points will be inserted at the end.
     * @param {%} % Arbitrary number of points
     * @returns {JXG.Polygon} Reference to the polygon
     */
    addPoints: function () {
        var args = Array.prototype.slice.call(arguments);

        return this.insertPoints.apply(this, [this.vertices.length-2].concat(args));
    },

    /**
     * Adds more points to the vertex list of the polygon, starting with index <tt><i</tt>
     * @param {Number} i The position where the new vertices are inserted, starting with 0.
     * @param {%} % Arbitrary number of points to insert.
     * @returns {JXG.Polygon} Reference to the polygon object
     */
    insertPoints: function () {
        var idx, i, npoints = [], tmp;

        if (arguments.length === 0) {
            return this;
        }

        idx = arguments[0];

        if (idx < 0 || idx > this.vertices.length-2) {
            return this;
        }

        for (i = 1; i < arguments.length; i++) {
            if (JXG.isPoint(arguments[i])) {
                npoints.push(arguments[i]);
            }
        }

        tmp = this.vertices.slice(0, idx+1).concat(npoints);
        this.vertices = tmp.concat(this.vertices.slice(idx+1));

        if (this.withLines) {
            tmp = this.borders.slice(0, idx);
            this.board.removeObject(this.borders[idx]);

            for (i = 0; i < npoints.length; i++) {
                tmp.push(JXG.createSegment(this.board, [this.vertices[idx+i], this.vertices[idx+i+1]], this.attr_line));
            }
            tmp.push(JXG.createSegment(this.board, [this.vertices[idx+npoints.length], this.vertices[idx+npoints.length+1]], this.attr_line));

            this.borders = tmp.concat(this.borders.slice(idx));
        }

        this.board.update();

        return this;
    },

    /**
     * Removes given set of vertices from the polygon
     * @param {%} % Arbitrary number of vertices as {@link JXG.Point} elements or index numbers
     * @returns {JXG.Polygon} Reference to the polygon
     */
    removePoints: function () {
        var i, j, idx, nvertices = [], nborders = [],
            nidx = [], partition = [];

        // partition:
        // in order to keep the borders which could be recycled, we have to partition
        // the set of removed points. I.e. if the points 1, 2, 5, 6, 7, 10 are removed,
        // the partition is
        //       1-2, 5-7, 10-10
        // this gives us the borders, that can be removed and the borders we have to create.


        // remove the last vertex which is identical to the first
        this.vertices = this.vertices.slice(0, this.vertices.length-1);

        // collect all valid parameters as indices in nidx
        for (i = 0; i < arguments.length; i++) {
            if (JXG.isPoint(arguments[i])) {
                idx = this.findPoint(arguments[i]);
            }

            if (JXG.isNumber(idx) && idx > -1 && idx < this.vertices.length && JXG.indexOf(nidx, idx) === -1) {
                nidx.push(idx);
            }
        }

        // sort the elements to be eliminated
        nidx = nidx.sort();
        nvertices = this.vertices.slice();
        nborders = this.borders.slice();

        // initialize the partition
        if (this.withLines) {
            partition.push([nidx[nidx.length-1]]);
        }

        // run through all existing vertices and copy all remaining ones to nvertices
        // compute the partition
        for (i = nidx.length-1; i > -1; i--) {
            nvertices[nidx[i]] = -1;

            if (this.withLines && (nidx[i] - 1 > nidx[i-1])) {
                partition[partition.length-1][1] = nidx[i];
                partition.push([nidx[i-1]]);
            }
        }

        // finalize the partition computation
        if (this.withLines) {
            partition[partition.length-1][1] = nidx[0];
        }

        // update vertices
        this.vertices = [];
        for (i = 0; i < nvertices.length; i++) {
            if (JXG.isPoint(nvertices[i])) {
                this.vertices.push(nvertices[i]);
            }
        }
        if (this.vertices[this.vertices.length-1].id !== this.vertices[0].id) {
            this.vertices.push(this.vertices[0]);
        }

        // delete obsolete and create missing borders
        if (this.withLines) {
            for (i = 0; i < partition.length; i++) {
                for (j = partition[i][1] - 1; j < partition[i][0] + 1; j++) {
                    // special cases
                    if (j < 0) {
                        // first vertex is removed, so the last border has to be removed, too
                        j = 0;
                        this.board.removeObject(this.borders[nborders.length-1]);
                        nborders[nborders.length-1] = -1;
                    } else if (j > nborders.length-1) {
                        j = nborders.length-1;
                    }

                    this.board.removeObject(this.borders[j]);
                    nborders[j] = -1;
                }

                // only create the new segment if it's not the closing border. the closing border is getting a special treatment at the end
                // the if clause is newer than the min/max calls inside createSegment; i'm sure this makes the min/max calls obsolete, but
                // just to be sure...
                if (partition[i][1] !== 0 && partition[i][0] !== nvertices.length-1) {
                    nborders[partition[i][0] - 1] = JXG.createSegment(this.board, [nvertices[Math.max(partition[i][1]-1, 0)], nvertices[Math.min(partition[i][0]+1, this.vertices.length-1)]], this.attr_line);
                }
            }

            this.borders = [];
            for (i = 0; i < nborders.length; i++) {
                if (nborders[i] !== -1) {
                    this.borders.push(nborders[i]);
                }
            }

            // if the first and/or the last vertex is removed, the closing border is created at the end.
            if (partition[0][1] === 5 || partition[partition.length-1][1] === 0) {
                this.borders.push(JXG.createSegment(this.board, [this.vertices[0], this.vertices[this.vertices.length-2]], this.attr_line));
            }
        }

        this.board.update();

        return this;
    },

    getParents: function () {
        var p = [], i;

        for (i = 0; i < this.vertices.length; i++) {
            p.push(this.vertices[i].id);
        }
        return p;
    },

    getAttributes: function () {
        var attr = JXG.GeometryElement.prototype.getAttributes.call(this), i;

        if (this.withLines) {
            attr.lines = attr.lines || {};
            attr.lines.ids = [];
            attr.lines.colors = [];

            for (i = 0; i < this.borders.length; i++) {
                attr.lines.ids.push(this.borders[i].id);
                attr.lines.colors.push(this.borders[i].visProp.strokecolor);
            }
        }

        return attr;
    },

    /**
     * Moves the line by the difference of two coordinates.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinates in screen/user units
     * @param {Array} oldcoords previous coordinates in screen/user units
     * @returns {JXG.Line}
     */
    setPositionDirectly: function (method, coords, oldcoords) {
        var dc, t, i, len,
            c = new JXG.Coords(method, coords, this.board),
            oldc = new JXG.Coords(method, oldcoords, this.board);

        len = this.vertices.length-1;
        for (i=0; i<len; i++) {
            if (!this.vertices[i].draggable()) {
                return this;
            }
        }

        dc = JXG.Math.Statistics.subtract(c.usrCoords, oldc.usrCoords);
        t = this.board.create('transform', dc.slice(1), {type:'translate'});
        t.applyOnce(this.vertices.slice(0,-1));
        
        return this;
    }
    
});


/**
 * @class A polygon is an area enclosed by a set of border lines which are determined by a list of points. Each two
 * consecutive points of the list define a line.
 * @pseudo
 * @constructor
 * @name Polygon
 * @type Polygon
 * @augments JXG.Polygon
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {Array} vertices The polygon's vertices. If the first and the last vertex don't match the first one will be
 * added to the array by the creator.
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var p3 = board.create('point', [4.0, 6.0]);
 * var p4 = board.create('point', [1.0, 3.0]);
 *
 * var pol = board.create('polygon', [p1, p2, p3, p4]);
 * </pre><div id="682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *  (function () {
 *   var board = JXG.JSXGraph.initBoard('682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [0.0, 2.0]),
 *       p2 = board.create('point', [2.0, 1.0]),
 *       p3 = board.create('point', [4.0, 6.0]),
 *       p4 = board.create('point', [1.0, 3.0]),
 *       cc1 = board.create('polygon', [p1, p2, p3, p4]);
 *  })();
 * </script><pre>
 */
JXG.createPolygon = function(board, parents, attributes) {
    var el, i, attr = JXG.copyAttributes(attributes, board.options, 'polygon');

    // Sind alles Punkte?
    for(i = 0; i < parents.length; i++) {
        parents[i] = JXG.getReference(board, parents[i]);
        if(!JXG.isPoint(parents[i]))
            throw new Error("JSXGraph: Can't create polygon with parent types other than 'point'.");
    }

    el = new JXG.Polygon(board, parents, attr);
    el.isDraggable = true;

    return el;
};


/**
 * @class Constructs a regular polygon. It needs two points which define the base line and the number of vertices.
 * @pseudo
 * @description Constructs a regular polygon. It needs two points which define the base line and the number of vertices, or a set of points.
 * @constructor
 * @name RegularPolygon
 * @type Polygon
 * @augments Polygon
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_Number} p1,p2,n The constructed regular polygon has n vertices and the base line defined by p1 and p2.
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 *
 * var pol = board.create('regularpolygon', [p1, p2, 5]);
 * </pre><div id="682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *  (function () {
 *   var board = JXG.JSXGraph.initBoard('682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [0.0, 2.0]),
 *       p2 = board.create('point', [2.0, 1.0]),
 *       cc1 = board.create('regularpolygon', [p1, p2, 5]);
 *  })();
 * </script><pre>
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [4.0,4.0]);
 * var p3 = board.create('point', [2.0,0.0]);
 *
 * var pol = board.create('regularpolygon', [p1, p2, p3]);
 * </pre><div id="096a78b3-bd50-4bac-b958-3be5e7df17ed" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('096a78b3-bd50-4bac-b958-3be5e7df17ed', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [0.0, 2.0]),
 *       p2 = board.create('point', [4.0, 4.0]),
 *       p3 = board.create('point', [2.0,0.0]),
 *       cc1 = board.create('regularpolygon', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
JXG.createRegularPolygon = function(board, parents, attributes) {
    var el, i, n, p = [], rot, c, len, pointsExist, attr;

    if (JXG.isNumber(parents[parents.length-1]) && parents.length!=3) {
        throw new Error("JSXGraph: A regular polygon needs two points and a number as input.");
    }

    len = parents.length;
    n = parents[len-1];
    if ((!JXG.isNumber(n) && !JXG.isPoint(JXG.getReference(board, n))) || n<3) {
        throw new Error("JSXGraph: The third parameter has to be number greater than 2 or a point.");
    }

    if (JXG.isPoint(JXG.getReference(board, n))) {  // Regular polygon given by n points
        n = len;
        pointsExist = true;
    } else {
        len--;
        pointsExist = false;
    }

    // The first two parent elements have to be points
    for(i=0; i<len; i++) {
        parents[i] = JXG.getReference(board, parents[i]);
        if(!JXG.isPoint(parents[i]))
            throw new Error("JSXGraph: Can't create regular polygon if the first two parameters aren't points.");
    }

    p[0] = parents[0];
    p[1] = parents[1];
    attr = JXG.copyAttributes(attributes, board.options, 'polygon', 'vertices');
    for (i=2;i<n;i++) {
        rot = board.create('transform', [Math.PI*(2.0-(n-2)/n),p[i-1]], {type:'rotate'});
        if (pointsExist) {
            p[i] = parents[i];
            p[i].addTransform(parents[i-2],rot);
        } else {
            if (JXG.isArray(attr.ids) && attr.ids.length >= n-2) {
                attr.id = attr.ids[i-2];
            }
            p[i] = board.create('point',[p[i-2],rot], attr);
			p[i].type = JXG.OBJECT_TYPE_CAS;
            
            // The next two lines of code are need to make regular polgonmes draggable
            // The new helper points are set to be draggable.
			p[i].isDraggable = true;
			p[i].visProp.fixed = false;
        }
    }
    attr = JXG.copyAttributes(attributes, board.options, 'polygon');
    el = board.create('polygon', p, attr);

    el.elType = 'regularpolygon';

    return el;
};

JXG.JSXGraph.registerElement('polygon', JXG.createPolygon);
JXG.JSXGraph.registerElement('regularpolygon', JXG.createRegularPolygon);


/*
    Copyright 2008-2011,
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview In this file the geometry element Curve is defined.
 */

/**
 * Curves are the common object for function graphs, parametric curves, polar curves, and data plots.
 * @class Creates a new curve object. Do not use this constructor to create a curve. Use {@link JXG.Board#create} with
 * type {@link Curve}, or {@link Functiongraph} instead.  
 * @augments JXG.GeometryElement
 * @param {string|JXG.Board} board The board the new curve is drawn on.
 * @param {Array} parents defining terms An array with the functon terms or the data points of the curve.
 * @param {Object} attributes Defines the visual appearance of the curve.
 * @see JXG.Board#generateName
 * @see JXG.Board#addCurve
  */
JXG.Curve = function (board, parents, attributes) {
    this.constructor(board, attributes, JXG.OBJECT_TYPE_CURVE, JXG.OBJECT_CLASS_CURVE);
 
    this.points = []; 
    /** 
     * Number of points on curves. This value changes
     * between numberPointsLow and numberPointsHigh.
     * It is set in {@link JXG.Curve#updateCurve}.
     */
    this.numberPoints = this.visProp.numberpointshigh; 
    
    this.bezierDegree = 1;

    this.dataX = null;
    this.dataY = null;

    if (parents[0]!=null) {
        this.varname = parents[0];
    } else {
        this.varname = 'x';
    }
    this.xterm = parents[1];  // function graphs: "x"
    this.yterm = parents[2];  // function graphs: e.g. "x^2"
    this.generateTerm(this.varname,this.xterm,this.yterm,parents[3],parents[4]);  // Converts GEONExT syntax into JavaScript syntax
    this.updateCurve();                        // First evaluation of the curve
    
    this.id = this.board.setId(this,'G');
    this.board.renderer.drawCurve(this);
    
    this.board.finalizeAdding(this);

    this.createGradient();
    this.elType = 'curve';
    this.createLabel();

    if (typeof this.xterm=='string') {
        this.notifyParents(this.xterm);
    }
    if (typeof this.yterm=='string') {
        this.notifyParents(this.yterm);
    }
};
JXG.Curve.prototype = new JXG.GeometryElement;


JXG.extend(JXG.Curve.prototype, /** @lends JXG.Curve.prototype */ {

    /**
     * Gives the default value of the left bound for the curve.
     * May be overwritten in {@link JXG.Curve#generateTerm}.
     * @returns {Number} Left bound for the curve.
     */
    minX: function () {
        if (this.visProp.curvetype=='polar') {
            return 0.0;
        } else {
            var leftCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0, 0], this.board);
            return leftCoords.usrCoords[1];
        }
    },

    /**
     * Gives the default value of the right bound for the curve.
     * May be overwritten in {@link JXG.Curve#generateTerm}.
     * @returns {Number} Right bound for the curve.
     */
    maxX: function () {
        var rightCoords;
        if (this.visProp.curvetype=='polar') {
            return 2.0*Math.PI;
        } else {
            rightCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [this.board.canvasWidth, 0], this.board);
            return rightCoords.usrCoords[1];
        }
    },

    /**
     * Treat the curve as curve with homogeneous coordinates
     * @param {Number} t A number between 0.0 and 1.0.
     * @return {Number} Always 1.0
     */
    Z: function (t) {
        return 1.0;
    },

    /**
     * Checks whether (x,y) is near the curve.
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @param {Number} start Optional start index for search on data plots. 
     * @return {Boolean} True if (x,y) is near the curve, False otherwise.
     */
    hasPoint: function (x, y, start) {
        var t, dist = Infinity,
            i, tX, tY,
            xi, yi, x0, y0, x1, y1, xy, den, lbda, 
            steps = this.visProp.numberpointslow,
            d = (this.maxX()-this.minX())/steps,
            prec = this.board.options.precision.hasPoint/this.board.unitX,
            checkPoint, len,
            suspendUpdate = true,
            invMat, c;

        prec = prec*prec;
        checkPoint = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board);
        x = checkPoint.usrCoords[1];
        y = checkPoint.usrCoords[2];
        
        if (this.transformations.length>0) {
            /** 
             * Transform the mouse/touch coordinates 
             * back to the original position of the curve.
             */
            this.updateTransformMatrix();
            invMat = JXG.Math.inverse(this.transformMat);
            c = JXG.Math.matVecMult(invMat, [1, x, y]);
            x = c[1];
            y = c[2];
        }
        
        if (this.visProp.curvetype=='parameter' 
            || this.visProp.curvetype=='polar' 
            || this.visProp.curvetype=='functiongraph') {
            
            // Brute fore search for a point on the curve close to the mouse pointer
            
            for (i=0,t=this.minX(); i<steps; i++) {
                tX = this.X(t,suspendUpdate);
                tY = this.Y(t,suspendUpdate);
                
                dist = (x-tX)*(x-tX)+(y-tY)*(y-tY);
                if (dist<prec) { return true; }
                t+=d;
            }
        } else if (this.visProp.curvetype == 'plot') {
            if (!JXG.exists(start) || start<0) {
                start = 0;
            }
            len = this.numberPoints; // Rough search quality
            for (i=start;i<len-1;i++) {
                xi  = this.X(i);
                yi  = this.Y(i);

                x0  = x - xi;
                y0  = y - yi;

                x1  = this.X(i+1) - xi;
                y1  = this.Y(i+1) - yi;
                
                den = x1*x1+y1*y1;
                dist = x0*x0+y0*y0;
                
                if (den>=JXG.Math.eps) {
                    xy = x0*x1+y0*y1;
                    lbda = xy/den;
                    dist -= lbda*xy;
                } else {
                    lbda = 0.0;
                }
                if (lbda>=0.0 && lbda<=1.0 && dist<prec) {
                    return true;
                }
            }
            return false;
        }
        return (dist<prec);
    },

    /**
     * Allocate points in the Coords array this.points
     */
    allocatePoints: function () {
        var i, len;
        
        len = this.numberPoints;
        
        if (this.points.length < this.numberPoints) {
            for (i = this.points.length; i < len; i++) {
                this.points[i] = new JXG.Coords(JXG.COORDS_BY_USER, [0,0], this.board);
            }
        }
    },

    /**
     * Computes for equidistant points on the x-axis the values of the function
     * @returns {JXG.Curve} Reference to the curve object.
     * @see JXG.Curve#updateCurve
     */
    update: function () {
        if (this.needsUpdate) {
            if (this.visProp.trace) {
                this.cloneToBackground(true);
            }
            this.updateCurve();
        }

        return this;
    },

    /**
     * Updates the visual contents of the curve.
     * @returns {JXG.Curve} Reference to the curve object.
     */
    updateRenderer: function () {
        if (this.needsUpdate && this.visProp.visible) {
            this.board.renderer.updateCurve(this);
            this.needsUpdate = false;

            // Update the label if visible.
            if(this.hasLabel && this.label.content.visProp.visible) {
                this.label.content.update();
                this.board.renderer.updateText(this.label.content);
            }
        }
        return this;
    },

    /**
     * For dynamic dataplots updateCurve can be used to compute new entries
     * for the arrays {@link JXG.Curve#dataX} and {@link JXG.Curve#dataY}. It
     * is used in {@link JXG.Curve#updateCurve}. Default is an empty method, can
     * be overwritten by the user.
     */
    updateDataArray: function () {
        // this used to return this, but we shouldn't rely on the user to implement it.
    },

    /**
     * Computes for equidistant points on the x-axis the values
     * of the function.
     * If the mousemove event triggers this update, we use only few
     * points. Otherwise, e.g. on mouseup, many points are used.
     * @see JXG.Curve#update
     * @returns {JXG.Curve} Reference to the curve object.
     */
    updateCurve: function () {
        var len, mi, ma, x, y, i,
            suspendUpdate = false;

        this.updateTransformMatrix();
        this.updateDataArray();
        mi = this.minX();
        ma = this.maxX();

        // Discrete data points
        if (this.dataX != null) { // x-coordinates are in an array
            this.numberPoints = this.dataX.length;
            len = this.numberPoints;
            this.allocatePoints();  // It is possible, that the array length has increased.
            for (i=0; i<len; i++) {
                x = i;
                if (this.dataY!=null) { // y-coordinates are in an array
                    y = i;
                    this.points[i].setCoordinates(JXG.COORDS_BY_USER, [this.dataX[i],this.dataY[i]], false); // The last parameter prevents rounding in usr2screen().
                } else {
                    y = this.X(x); // discrete x data, continuous y data
                    this.points[i].setCoordinates(JXG.COORDS_BY_USER, [this.dataX[i],this.Y(y,suspendUpdate)], false); // The last parameter prevents rounding in usr2screen().
                }
                //this.points[i].setCoordinates(JXG.COORDS_BY_USER, [this.X(x,suspendUpdate),this.Y(y,suspendUpdate)], false); // The last parameter prevents rounding in usr2screen().
                this.updateTransform(this.points[i]);
                suspendUpdate = true;
            }
        } else { // continuous x data
            if (this.visProp.doadvancedplot) {
                this.updateParametricCurve(mi, ma, len);
            } else {
                if (this.board.updateQuality==this.board.BOARD_QUALITY_HIGH) {
                    this.numberPoints = this.visProp.numberpointshigh;
                } else {
                    this.numberPoints = this.visProp.numberpointslow;
                }
                this.allocatePoints();  // It is possible, that the array length has increased.
                this.updateParametricCurveNaive(mi, ma, this.numberPoints);
            }
            len = this.numberPoints;
            for (i=0; i<len; i++) {
                this.updateTransform(this.points[i]);
            }
        }

        return this;
    },

    updateTransformMatrix: function() {
        var t, c, i,
            len = this.transformations.length;

        this.transformMat = [[1,0,0], [0,1,0], [0,0,1]];
        
        for (i = 0; i < len; i++) {
            t = this.transformations[i];
            t.update();
            this.transformMat = JXG.Math.matMatMult(t.matrix, this.transformMat);
        }
    
        return this;
    },
    
    /**
     * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#visProp.doadvancedplot} is <tt>false</tt>.
     * @param {Number} mi Left bound of curve
     * @param {Number} ma Right bound of curve
     * @param {Number} len Number of data points
     * @returns {JXG.Curve} Reference to the curve object.
     */
    updateParametricCurveNaive: function(mi, ma, len) {
        var i, t,
            suspendUpdate = false,
            stepSize = (ma-mi)/len;

        for (i=0; i<len; i++) {
            t = mi+i*stepSize;
            this.points[i].setCoordinates(JXG.COORDS_BY_USER, [this.X(t,suspendUpdate),this.Y(t,suspendUpdate)], false); // The last parameter prevents rounding in usr2screen().
            suspendUpdate = true;
        }
        return this;
    },

    /**
     * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#visProp.doadvancedplot} is <tt>true</tt>.
     * @param {Number} mi Left bound of curve
     * @param {Number} ma Right bound of curve
     * @param {Number} len Number of data points
     * @returns {JXG.Curve} Reference to the curve object.
     */
    updateParametricCurve: function(mi, ma) {
        var i, t, t0,
            suspendUpdate = false,
            po = new JXG.Coords(JXG.COORDS_BY_USER, [0,0], this.board),
            x, y, x0, y0, top, depth,
            MAX_DEPTH,
            MAX_XDIST,
            MAX_YDIST,
            dyadicStack = [],
            depthStack = [],
            pointStack = [],
            divisors = [],
            distOK = false,
            j = 0,
            d,
            distFromLine = function(p1, p2, p0) {
                var x0 = p0[1] - p1[1],
                    y0 = p0[2] - p1[2],
                    x1 = p2[0] - p1[1],
                    y1 = p2[1] - p1[2],
                    den = x1 * x1 + y1 * y1,
                    lbda, d;

                if (den >= JXG.Math.eps) {
                    lbda = (x0 * x1 + y0 * y1) / den;
                    if (lbda>0.0) {
                        if (lbda<=1.0) {
                            x0 -= lbda*x1;
                            y0 -= lbda*y1;
                            
                        } else { // lbda = 1.0;
                            x0 -= x1;
                            y0 -= y1;
                        }
                    }
                }
                d = x0*x0 + y0*y0;
                return Math.sqrt(d);
            };

        if (this.board.updateQuality == this.board.BOARD_QUALITY_LOW) {
            MAX_DEPTH = 15;
            MAX_XDIST = 10;
            MAX_YDIST = 10;
        } else {
            MAX_DEPTH = 21;
            MAX_XDIST = 0.7;
            MAX_YDIST = 0.7;
        }
        
        divisors[0] = ma-mi;
        for (i = 1; i < MAX_DEPTH; i++) {
            divisors[i] = divisors[i-1]*0.5;
        }

        i = 1;
        dyadicStack[0] = 1;
        depthStack[0] = 0;
        
        t = mi;
        po.setCoordinates(JXG.COORDS_BY_USER, [this.X(t,suspendUpdate),this.Y(t,suspendUpdate)], false);
        
        // Now, there was a first call to the functions defining the curve.
        // Defining elements like sliders have been evaluated.
        // Therefore, we can set suspendUpdate to false, so that these defining elements
        // need not be evaluated anymore for the rest of the plotting.
        suspendUpdate = true; 
        x0 = po.scrCoords[1];
        y0 = po.scrCoords[2];
        t0 = t;

        t = ma;
        po.setCoordinates(JXG.COORDS_BY_USER, [this.X(t,suspendUpdate),this.Y(t,suspendUpdate)], false);
        x = po.scrCoords[1];
        y = po.scrCoords[2];

        pointStack[0] = [x,y];

        top = 1;
        depth = 0;

        this.points = [];
        this.points[j++] = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x0, y0], this.board);

        do {
            distOK = this.isDistOK(x-x0, y-y0, MAX_XDIST, MAX_YDIST) || this.isSegmentOutside(x0,y0,x,y);
            while (depth < MAX_DEPTH 
                   && (!distOK || depth < 6) 
                   && (depth <= 7 || this.isSegmentDefined(x0, y0, x, y)) ) {
                // We jump out of the loop if
                // * depth>=MAX_DEPTH or
                // * (depth>=6 and distOK) or
                // * (depth>7 and segment is not defined)
                
                dyadicStack[top] = i;
                depthStack[top] = depth;
                pointStack[top] = [x,y];
                top++;

                i = 2*i-1;
                depth++;                   // Here, depth is increased and may reach MAX_DEPTH
                t = mi+i*divisors[depth];  // In that case, t is undefined and we will see a jump
                                           // in the curve.

                po.setCoordinates(JXG.COORDS_BY_USER, [this.X(t,suspendUpdate),this.Y(t,suspendUpdate)], false);
                x = po.scrCoords[1];
                y = po.scrCoords[2];
                distOK = this.isDistOK(x-x0, y-y0, MAX_XDIST, MAX_YDIST) || this.isSegmentOutside(x0,y0,x,y);
            }
            
            if (j > 1) {
                d = distFromLine(this.points[j-2].scrCoords, [x,y], this.points[j-1].scrCoords);
                if (d<0.015) {
                    j--;
                }
            }
            this.points[j] = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x, y], this.board);
            j++;

            x0 = x;
            y0 = y;
            t0 = t;

            top--;
            x = pointStack[top][0];
            y = pointStack[top][1];
            depth = depthStack[top]+1;
            i = dyadicStack[top]*2;

        } while (top > 0 && j<500000);
        this.numberPoints = this.points.length;

        return this;
    },

    /**
     * Crude and cheap test if the segment defined by the two points <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt> is
     * outside the viewport of the board. All parameters have to be given in screen coordinates.
     * @param {Number} x0
     * @param {Number} y0
     * @param {Number} x1
     * @param {Number} y1
     * @returns {Boolean} <tt>true</tt> if the given segment is outside the visible area.
     */
    isSegmentOutside: function (x0, y0, x1, y1) {
        return (y0 < 0 && y1 < 0) || (y0 > this.board.canvasHeight && y1 > this.board.canvasHeight) ||
               (x0 < 0 && x1 < 0) || (x0 > this.board.canvasWidth && x1 > this.board.canvasWidth);
    },

    /**
     * Compares the absolute value of <tt>dx</tt> with <tt>MAXX</tt> and the absolute value of <tt>dy</tt>
     * with <tt>MAXY</tt>.
     * @param {Number} dx
     * @param {Number} dy
     * @param {Number} MAXX
     * @param {Number} MAXY
     * @returns {Boolean} <tt>true</tt>, if <tt>|dx| &lt; MAXX</tt> and <tt>|dy| &lt; MAXY</tt>.
     */
    isDistOK: function (dx, dy, MAXX, MAXY) {
        return (Math.abs(dx) < MAXX && Math.abs(dy) < MAXY) && !isNaN(dx+dy);
    },

    isSegmentDefined: function (x0,y0,x1,y1) {
        return !(isNaN(x0 + y0) && isNaN(x1 + y1));
    },

    /**
     * Applies the transformations of the curve to the given point <tt>p</tt>.
     * Before using it, {@link JXG.Curve#updateTransformMatrix} has to be called.
     * @param {JXG.Point} p
     * @returns {JXG.Point} The given point.
     */
    updateTransform: function (p) {
        var c, len = this.transformations.length;
        /*
        for (i = 0; i < len; i++) {
            t = this.transformations[i];
            t.update();
            c = JXG.Math.matVecMult(t.matrix, p.usrCoords);
            p.setCoordinates(JXG.COORDS_BY_USER, [c[1], c[2]]);
        }
        */
        if (len>0) {
            c = JXG.Math.matVecMult(this.transformMat, p.usrCoords);
            p.setCoordinates(JXG.COORDS_BY_USER, [c[1], c[2]]);
        }
        
        return p;
    },

    /**
     * Add transformations to this curve.
     * @param {JXG.Transform|Array} transform Either one {@link JXG.Transform} or an array of {@link JXG.Transform}s.
     * @returns {JXG.Curve} Reference to the curve object.
     */
    addTransform: function (transform) {
        var i,
            list = JXG.isArray(transform) ? transform : [transform],
            len = list.length;
        
        for (i = 0; i < len; i++) {
            this.transformations.push(list[i]);
        }
        
        return this;
    },

    /**
     * Translates the object by <tt>(x, y)</tt>.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords array of translation vector.
     * @returns {JXG.Curve} Reference to the curve object.
     */
    setPosition: function (method, coords) {
        var t, obj, len=0, i;
        
        if (JXG.exists(this.parents)) {
            len = this.parents.length;
        }
        
        for (i=0; i<len; i++) {
            obj = JXG.getRef(this.board, this.parents[i]);
            
            if (!obj.draggable()) {
                return this;
            }
        }

        /**
         * We distinguish two cases:
         * 1) curves which depend on free elements, i.e. arcs and sectors
         * 2) other curves
         *
         * In the first case we simply transform the parents elements
         * In the second case we add a transform to the curve.
         */

        coords = new JXG.Coords(method, coords, this.board);
        t = this.board.create('transform', coords.usrCoords.slice(1),{type:'translate'});
        
        if (len>0) {   // First case
            for (i=0; i<len; i++) {
                obj = JXG.getRef(this.board, this.parents[i]);
                t.applyOnce(obj);
            }
        } else {      // Second case
            if (this.transformations.length > 0 
                && this.transformations[this.transformations.length-1].isNumericMatrix) {
            
                this.transformations[this.transformations.length-1].melt(t);
            } else {
                this.addTransform(t);
            }
        }
        return this;
    },

    /**
     * Moves the cuvre by the difference of two coordinates.
     * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinates in screen/user units
     * @param {Array} oldcoords previous coordinates in screen/user units
     * @returns {JXG.Curve}
     */
    setPositionDirectly: function (method, coords, oldcoords) {
        var c = new JXG.Coords(method, coords, this.board),
            oldc = new JXG.Coords(method, oldcoords, this.board),
            dc = JXG.Math.Statistics.subtract(c.usrCoords, oldc.usrCoords);
            
        this.setPosition(JXG.COORDS_BY_USER, dc);
        
        return this;
    },
    
    /**
     * Generate the method curve.X() in case curve.dataX is an array
     * and generate the method curve.Y() in case curve.dataY is an array.
     * @see JXG.Math.Geometry#generateTerm.
     * @private
     * @param {String} which Either 'X' or 'Y'
     * @return {Function} 
     **/
    interpolationFunctionFromArray: function(which) {
        var data = 'data' + which;
        return function(t, suspendedUpdate) { 
                var i, f1, f2, 
                    arr = this[data],
                    len = arr.length,
                    z, t0, t1, 
                    f=[], j;

                if (isNaN(t)) {
                    return NaN;
                }
                
                if (t < 0) {
                    if (JXG.isFunction(arr[0])) {
                       return arr[0]();
                    } else {
                       return arr[0];
                    }
                }
 
                if (this.bezierDegree==3) {
                    len /=3;
                    if (t >= len) {
                        if (JXG.isFunction(arr[arr.length-1])) {
                            return arr[arr.length-1]();
                        } else {
                            return arr[arr.length-1];
                        }
                    }
                           
                    i = Math.floor(t) * 3,
                    t0 = t % 1,
                    t1 = 1 - t0;             
                    
                    for (j=0;j<4;j++) {
                        if (JXG.isFunction(arr[i+j])) {
                            f[j] = arr[i+j]();
                        } else {
                            f[j] = arr[i+j];
                        }
                    }
                    return t1*t1*(t1*f[0] + 3*t0*f[1]) + (3*t1*f[2] + t0*f[3])*t0*t0;
                } else {
                    if (t>len-2) {
                        i = len-2;
                    } else {
                        i = parseInt(Math.floor(t));
                    }
                        
                    if (i==t) {
                        if (JXG.isFunction(arr[i])) {
                            return arr[i](); 
                        } else {
                            return arr[i]; 
                        }
                    } else {
                        for (j=0;j<2;j++) {
                            if (JXG.isFunction(arr[i+j])) {
                                f[j] = arr[i+j]();
                            } else {
                                f[j] = arr[i+j];
                            }
                        }
                        return f[0]+(f[1]-f[0])*(t-i);
                    }
                }
            };
    },
    /**
     * Converts the GEONExT syntax of the defining function term into JavaScript.
     * New methods X() and Y() for the Curve object are generated, further
     * new methods for minX() and maxX().
     * @see JXG.GeonextParser#geonext2JS.
     */
    generateTerm: function (varname, xterm, yterm, mi, ma) {
        var fx, fy;

        // Generate the methods X() and Y()
        if (JXG.isArray(xterm)) {
            // Discrete data
            this.dataX = xterm;
            
            this.numberPoints = this.dataX.length;
            this.X = this.interpolationFunctionFromArray('X');
            this.visProp.curvetype = 'plot';
            this.isDraggable = true;
        } else {
            // Continuous data
            this.X = JXG.createFunction(xterm, this.board, varname);
            if (JXG.isString(xterm)) {
                this.visProp.curvetype = 'functiongraph';
            } else if (JXG.isFunction(xterm) || JXG.isNumber(xterm)) {
                this.visProp.curvetype = 'parameter';
            }

            this.isDraggable = true;
        }

        if (JXG.isArray(yterm)) {
            this.dataY = yterm;
            this.Y = this.interpolationFunctionFromArray('Y');
        } else {
            this.Y = JXG.createFunction(yterm,this.board,varname);
        }

        /**
          * Polar form
          * Input data is function xterm() and offset coordinates yterm
          */
        if (JXG.isFunction(xterm) && JXG.isArray(yterm)) {
            // Xoffset, Yoffset
            fx = JXG.createFunction(yterm[0],this.board,'');
            fy = JXG.createFunction(yterm[1],this.board,'');
            this.X = function(phi){return (xterm)(phi)*Math.cos(phi)+fx();};
            this.Y = function(phi){return (xterm)(phi)*Math.sin(phi)+fy();};
            this.visProp.curvetype = 'polar';
        }

        // Set the bounds
        // lower bound
        if (mi!=null) this.minX = JXG.createFunction(mi,this.board,'');
        if (ma!=null) this.maxX = JXG.createFunction(ma,this.board,'');
    },

    /**
     * Finds dependencies in a given term and notifies the parents by adding the
     * dependent object to the found objects child elements.
     * @param {String} contentStr String containing dependencies for the given object.
     */
    notifyParents: function (contentStr) {
        JXG.GeonextParser.findDependencies(this,contentStr, this.board);
    },

    // documented in geometry element
    getLabelAnchor: function() {
        var c, x, y, 
            ax = 0.05*this.board.canvasWidth,
            ay = 0.05*this.board.canvasHeight,
            bx = 0.95*this.board.canvasWidth, 
            by = 0.95*this.board.canvasHeight;
        
        switch (this.visProp.label.position) {
            case 'ulft':
                x = ax; y = ay; break;
            case 'llft':
                x = ax; y = by; break;
            case 'rt':
                x = bx; y = 0.5*by; break;
            case 'lrt':
                x = bx; y = by; break;
            case 'urt':
                x = bx; y = ay; break;
            case 'top':
                x = 0.5*bx; y = ay; break;
            case 'bot':
                x = 0.5*bx; y = by; break;
            case 'lft':
            default:
                x = ax; y = 0.5*by; break;
        }
        c = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x, y], this.board);
        return JXG.Math.Geometry.projectCoordsToCurve(c.usrCoords[1],c.usrCoords[2], 0.0, this, this.board)[0];
    },

    // documented in geometry element
    cloneToBackground: function () {
        var copy = {}, er;

        copy.id = this.id + 'T' + this.numTraces;
        copy.elementClass = JXG.OBJECT_CLASS_CURVE;
        this.numTraces++;

        copy.points = this.points.slice(0);
        copy.numberPoints = this.numberPoints;
        copy.board = this.board;
        copy.visProp = JXG.deepCopy(this.visProp, this.visProp.traceattributes, true);
        copy.visProp.layer = this.board.options.layer.trace;
        copy.visProp.curvetype = this.visProp.curvetype;

        JXG.clearVisPropOld(copy);
        
        er = this.board.renderer.enhancedRendering;
        this.board.renderer.enhancedRendering = true;
        this.board.renderer.drawCurve(copy);
        this.board.renderer.enhancedRendering = er;
        this.traces[copy.id] = copy.rendNode;

        return this;
    },

    // already documented in GeometryElement
    bounds: function () {
        var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity,
            l = this.points.length, i;

        for (i = 0; i < l; i++) {
            if (minX > this.points[i].usrCoords[1]) {
                minX = this.points[i].usrCoords[1];
            }

            if (maxX < this.points[i].usrCoords[1]) {
                maxX = this.points[i].usrCoords[1];
            }

            if (minY > this.points[i].usrCoords[2]) {
                minY = this.points[i].usrCoords[2];
            }

            if (maxY < this.points[i].usrCoords[2]) {
                maxY = this.points[i].usrCoords[2];
            }
        }

        return [minX, maxY, maxX, minY];
    }
});


/**
 * @class This element is used to provide a constructor for curve, which is just a wrapper for element {@link Curve}. 
 * A curve is a mapping from R to R^2. t mapsto (x(t),y(t)). The graph is drawn for t in the interval [a,b]. 
 * <p>
 * The following types of curves can be plotted:
 * <ul>
 *  <li> parametric curves: t mapsto (x(t),y(t)), where x() and y() are univariate functions.
 *  <li> polar curves: curves commonly written with polar equations like spirals and cardioids.
 *  <li> data plots: plot linbe segments through a given list of coordinates.
 * </ul>
 * @pseudo
 * @description
 * @name Curve
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 *
 * @param {function,number_function,number_function,number_function,number} x,y,a_,b_ Parent elements for Parametric Curves. 
 *                     <p>
 *                     x describes the x-coordinate of the curve. It may be a function term in one variable, e.g. x(t). 
 *                     In case of x being of type number, x(t) is set to  a constant function.
 *                     this function at the values of the array.
 *                     </p>
 *                     <p>
 *                     y describes the y-coordinate of the curve. In case of a number, y(t) is set to the constant function
 *                     returning this number. 
 *                     </p>
 *                     <p>
 *                     Further parameters are an optional number or function for the left interval border a, 
 *                     and an optional number or function for the right interval border b. 
 *                     </p>
 *                     <p>
 *                     Default values are a=-10 and b=10.
 *                     </p>
 * @param {array_array,function,number} x,y Parent elements for Data Plots.
 *                     <p>
 *                     x and y are arrays contining the x and y coordinates of the data points which are connected by
 *                     line segments. The individual entries of x and y may also be functions.
 *                     In case of x being an array the curve type is data plot, regardless of the second parameter and 
 *                     if additionally the second parameter y is a function term the data plot evaluates.
 *                     </p>
 * @param {function_array,function,number_function,number_function,number} r,offset_,a_,b_ Parent elements for Polar Curves.
 *                     <p>
 *                     The first parameter is a function term r(phi) describing the polar curve.
 *                     </p>
 *                     <p>
 *                     The second parameter is the offset of the curve. It has to be
 *                     an array containing numbers or functions describing the offset. Default value is the origin [0,0].
 *                     </p>
 *                     <p>
 *                     Further parameters are an optional number or function for the left interval border a, 
 *                     and an optional number or function for the right interval border b. 
 *                     </p>
 *                     <p>
 *                     Default values are a=-10 and b=10.
 *                     </p>
 * @see JXG.Curve
 * @example
 * // Parametric curve
 * // Create a curve of the form (t-sin(t), 1-cos(t), i.e.
 * // the cycloid curve.
 *   var graph = board.create('curve', 
 *                        [function(t){ return t-Math.sin(t);}, 
 *                         function(t){ return 1-Math.cos(t);},
 *                         0, 2*Math.PI]
 *                     );
 * </pre><div id="af9f818b-f3b6-4c4d-8c4c-e4a4078b726d" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var c1_board = JXG.JSXGraph.initBoard('af9f818b-f3b6-4c4d-8c4c-e4a4078b726d', {boundingbox: [-1, 5, 7, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var graph1 = c1_board.create('curve', [function(t){ return t-Math.sin(t);},function(t){ return 1-Math.cos(t);},0, 2*Math.PI]);
 * </script><pre>
 * @example
 * // Data plots
 * // Connect a set of points given by coordinates with dashed line segments.
 * // The x- and y-coordinates of the points are given in two separate 
 * // arrays.
 *   var x = [0,1,2,3,4,5,6,7,8,9];
 *   var y = [9.2,1.3,7.2,-1.2,4.0,5.3,0.2,6.5,1.1,0.0];
 *   var graph = board.create('curve', [x,y], {dash:2});
 * </pre><div id="7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var c3_board = JXG.JSXGraph.initBoard('7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83', {boundingbox: [-1,10,10,-1], axis: true, showcopyright: false, shownavigation: false});
 *   var x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
 *   var y = [9.2, 1.3, 7.2, -1.2, 4.0, 5.3, 0.2, 6.5, 1.1, 0.0];
 *   var graph3 = c3_board.create('curve', [x,y], {dash:2});
 * </script><pre>
 * @example
 * // Polar plot
 * // Create a curve with the equation r(phi)= a*(1+phi), i.e.
 * // a cardioid.
 *   var a = board.create('slider',[[0,2],[2,2],[0,1,2]]);
 *   var graph = board.create('curve', 
 *                        [function(phi){ return a.Value()*(1-Math.cos(phi));}, 
 *                         [1,0], 
 *                         0, 2*Math.PI]
 *                     );
 * </pre><div id="d0bc7a2a-8124-45ca-a6e7-142321a8f8c2" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var c2_board = JXG.JSXGraph.initBoard('d0bc7a2a-8124-45ca-a6e7-142321a8f8c2', {boundingbox: [-3,3,3,-3], axis: true, showcopyright: false, shownavigation: false});
 *   var a = c2_board.create('slider',[[0,2],[2,2],[0,1,2]]);
 *   var graph2 = c2_board.create('curve', [function(phi){ return a.Value()*(1-Math.cos(phi));}, [1,0], 0, 2*Math.PI]);
 * </script><pre>
 */
JXG.createCurve = function(board, parents, attributes) {
    var attr = JXG.copyAttributes(attributes, board.options, 'curve');
    return new JXG.Curve(board, ['x'].concat(parents), attr);
};

JXG.JSXGraph.registerElement('curve', JXG.createCurve);

/**
 * @class This element is used to provide a constructor for functiongraph, which is just a wrapper for element {@link Curve} with {@link JXG.Curve#X()}
 * set to x. The graph is drawn for x in the interval [a,b].
 * @pseudo
 * @description
 * @name Functiongraph
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 * @param {function_number,function_number,function} f,a_,b_ Parent elements are a function term f(x) describing the function graph. 
 *         <p>
 *         Further, an optional number or function for the left interval border a, 
 *         and an optional number or function for the right interval border b. 
 *         <p>
 *         Default values are a=-10 and b=10.
 * @see JXG.Curve
 * @example
 * // Create a function graph for f(x) = 0.5*x*x-2*x
 *   var graph = board.create('functiongraph', 
 *                        [function(x){ return 0.5*x*x-2*x;}, -2, 4]
 *                     );
 * </pre><div id="efd432b5-23a3-4846-ac5b-b471e668b437" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var alex1_board = JXG.JSXGraph.initBoard('efd432b5-23a3-4846-ac5b-b471e668b437', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false});
 *   var graph = alex1_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, 4]);
 * </script><pre>
 * @example
 * // Create a function graph for f(x) = 0.5*x*x-2*x with variable interval
 *   var s = board.create('slider',[[0,4],[3,4],[-2,4,5]]);
 *   var graph = board.create('functiongraph', 
 *                        [function(x){ return 0.5*x*x-2*x;}, 
 *                         -2, 
 *                         function(){return s.Value();}]
 *                     );
 * </pre><div id="4a203a84-bde5-4371-ad56-44619690bb50" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var alex2_board = JXG.JSXGraph.initBoard('4a203a84-bde5-4371-ad56-44619690bb50', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false});
 *   var s = alex2_board.create('slider',[[0,4],[3,4],[-2,4,5]]);
 *   var graph = alex2_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, function(){return s.Value();}]);
 * </script><pre>
 */
JXG.createFunctiongraph = function(board, parents, attributes) {
    var attr, par = ["x","x"].concat(parents);

    attr = JXG.copyAttributes(attributes, board.options, 'curve');
    attr['curvetype'] = 'functiongraph';
    return new JXG.Curve(board, par, attr);
};

JXG.JSXGraph.registerElement('functiongraph', JXG.createFunctiongraph);
JXG.JSXGraph.registerElement('plot', JXG.createFunctiongraph);


/**
 * TODO
 * Create a dynamic spline interpolated curve given by sample points p_1 to p_n.
 * @param {JXG.Board} board Reference to the board the spline is drawn on.
 * @param {Array} parents Array of points the spline interpolates
 * @param {Object} attributes Define color, width, ... of the spline
 * @type JXG.Curve
 * @return Returns reference to an object of type JXG.Curve.
 */
JXG.createSpline = function(board, parents, attributes) {
    var F;
    F = function() {
        var D, x=[], y=[];
        
        var fct = function (t,suspended) {
            var i, j;
        
            if (!suspended) {
                x = [];
                y = [];

                // given as [x[], y[]]
                if(parents.length == 2 && JXG.isArray(parents[0]) && JXG.isArray(parents[1]) && parents[0].length == parents[1].length) {
                    for(i=0; i<parents[0].length; i++) {
                        if(typeof parents[0][i] == 'function')
                            x.push(parents[0][i]());
                        else
                            x.push(parents[0][i]);
                        if(typeof parents[1][i] == 'function')
                            y.push(parents[1][i]());
                        else
                            y.push(parents[1][i]);
                    }
                } else {
                    for(i=0; i<parents.length; i++) {
                        if(JXG.isPoint(parents[i])) {
                            //throw new Error("JSXGraph: JXG.createSpline: Parents has to be an array of JXG.Point.");
                            x.push(parents[i].X());
                            y.push(parents[i].Y());
                        } else if (JXG.isArray(parents[i]) && parents[i].length == 2) {     // given as [[x1,y1], [x2, y2], ...]
                            for(i=0; i<parents.length; i++) {
                                if(typeof parents[i][0] == 'function')
                                    x.push(parents[i][0]());
                                else
                                    x.push(parents[i][0]);
                                if(typeof parents[i][1] == 'function')
                                    y.push(parents[i][1]());
                                else
                                    y.push(parents[i][1]);
                            }
                        }
                    }
                }
        
                // The array D has only to be calculated when the position of one or more sample point
                // changes. otherwise D is always the same for all points on the spline.
                D = JXG.Math.Numerics.splineDef(x, y);
            }
            return JXG.Math.Numerics.splineEval(t, x, y, D);
        };
        return fct;
    };
    return board.create('curve', ["x", F()], attributes);
};

/**
 * Register the element type spline at JSXGraph
 * @private
 */
JXG.JSXGraph.registerElement('spline', JXG.createSpline);

/**
 * @class This element is used to provide a constructor for Riemann sums, which is realized as a special curve. 
 * The returned element has the method Value() which returns the sum of the areas of the rectangles.
 * @pseudo
 * @description
 * @name Riemannsum
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 * @param {function_number,function_string,function_function,number_function,number} f,n,type_,a_,b_ Parent elements of Riemannsum are a 
 *         function term f(x) describing the function graph which is filled by the Riemann rectangles.
 *         <p>
 *         n determines the number of rectangles, it is either a fixed number or a function.
 *         <p>
 *         type is a string or function returning one of the values:  'left', 'right', 'middle', 'lower', 'upper', or 'trapezodial'.
 *         Default value is 'left'.
 *         <p>
 *         Further parameters are an optional number or function for the left interval border a, 
 *         and an optional number or function for the right interval border b. 
 *         <p>
 *         Default values are a=-10 and b=10.
 * @see JXG.Curve
 * @example
 * // Create Riemann sums for f(x) = 0.5*x*x-2*x.
 *   var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1});
 *   var f = function(x) { return 0.5*x*x-2*x; };
 *   var r = board.create('riemannsum', 
 *               [f, function(){return s.Value();}, 'upper', -2, 5],
 *               {fillOpacity:0.4}
 *               );
 *   var g = board.create('functiongraph',[f, -2, 5]);
 *   var t = board.create('text',[-1,-1, function(){ return 'Sum=' + r.Value().toFixed(4); }]);
 * </pre><div id="940f40cc-2015-420d-9191-c5d83de988cf" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var rs1_board = JXG.JSXGraph.initBoard('940f40cc-2015-420d-9191-c5d83de988cf', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false});
 *   var f = function(x) { return 0.5*x*x-2*x; };
 *   var s = rs1_board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1});
 *   var r = rs1_board.create('riemannsum', [f, function(){return s.Value();}, 'upper', -2, 5], {fillOpacity:0.4});
 *   var g = rs1_board.create('functiongraph', [f, -2, 5]);
 *   var t = board.create('text',[-1,-1, function(){ return 'Sum=' + r.Value().toFixed(4); }]);
 * </script><pre>
 */
JXG.createRiemannsum = function(board, parents, attributes) {
    var n, type, f, par, c, attr;
    
    attr = JXG.copyAttributes(attributes, board.options, 'riemannsum');
    attr['curvetype'] = 'plot';

    f = parents[0]; 
    n = JXG.createFunction(parents[1],board,'');
    if (n==null) {
        throw new Error("JSXGraph: JXG.createRiemannsum: argument '2' n has to be number or function." +
                        "\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]");
    }

    type = JXG.createFunction(parents[2],board,'',false);
    if (type==null) {
        throw new Error("JSXGraph: JXG.createRiemannsum: argument 3 'type' has to be string or function." +
                        "\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]");
    }

    par = [[0], [0]].concat(parents.slice(3));
    
    c = board.create('curve', par, attr);
    
    // Value(): Return the "Riemann sum"
    c.sum = 0.0;
    c.Value = function() { return this.sum; };
    
    c.updateDataArray = function() {
        var u = JXG.Math.Numerics.riemann(f, n(), type(), this.minX(), this.maxX());
        this.dataX = u[0];
        this.dataY = u[1];
        // Update "Riemann sum"
        this.sum = u[2];
    };

    return c;
};

JXG.JSXGraph.registerElement('riemannsum', JXG.createRiemannsum);

/**
 * @class This element is used to provide a constructor for travce curve (simple locus curve), which is realized as a special curve. 
 * @pseudo
 * @description
 * @name Tracecurve
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 * @param {Point,Point} Parent elements of Tracecurve are a 
 *         glider point and a point whose locus is traced.
 * @see JXG.Curve
 * @example
 * // Create trace curve.
    var c1 = board.create('circle',[[0, 0], [2, 0]]),
        p1 = board.create('point',[-3, 1]),
        g1 = board.create('glider',[2, 1, c1]),
        s1 = board.create('segment',[g1, p1]),
        p2 = board.create('midpoint',[s1]),
        curve = board.create('tracecurve', [g1, p2]);
    
 * </pre><div id="5749fb7d-04fc-44d2-973e-45c1951e29ad" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var tc1_board = JXG.JSXGraph.initBoard('5749fb7d-04fc-44d2-973e-45c1951e29ad', {boundingbox: [-4, 4, 4, -4], axis: false, showcopyright: false, shownavigation: false});
 *   var c1 = tc1_board.create('circle',[[0, 0], [2, 0]]),
 *       p1 = tc1_board.create('point',[-3, 1]),
 *       g1 = tc1_board.create('glider',[2, 1, c1]),
 *       s1 = tc1_board.create('segment',[g1, p1]),
 *       p2 = tc1_board.create('midpoint',[s1]),
 *       curve = tc1_board.create('tracecurve', [g1, p2]);
 * </script><pre>
 */
JXG.createTracecurve = function(board, parents, attributes) {
    var c, glider, tracepoint, attr;
    
    if (parents.length!=2) {
        throw new Error("JSXGraph: Can't create trace curve with given parent'" +
                        "\nPossible parent types: [glider, point]");
    }
    
    glider = JXG.getRef(this.board, parents[0]);
    tracepoint = JXG.getRef(this.board, parents[1]);

    if (glider.type != JXG.OBJECT_TYPE_GLIDER || !JXG.isPoint(tracepoint)) {
        throw new Error("JSXGraph: Can't create trace curve with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [glider, point]");
    }

    attr = JXG.copyAttributes(attributes, board.options, 'tracecurve');
    attr['curvetype'] = 'plot';
  
    c = board.create('curve',[[0],[0]], attr);

    c.updateDataArray = function(){
        var i, step, t, el, pEl, x, y, v,
            le = attr.numberpoints, 
            from,
            savePos = glider.position, 
            slideObj = glider.slideObject,
            mi = slideObj.minX(),
            ma = slideObj.maxX(), savetrace;

        step = (ma-mi)/le;                    // set step width
        this.dataX = [];
        this.dataY = [];
        /*
         * For gliders on circles and lines a closed curve is computed.
         * For gliders on curves the curve is not closed.
         */
        if (slideObj.elementClass!=JXG.OBJECT_CLASS_CURVE) {   
            le++;
        }
        for (i=0; i<le; i++) {                    // Loop over all steps
            t = mi + i*step;
            x = slideObj.X(t)/slideObj.Z(t);
            y = slideObj.Y(t)/slideObj.Z(t);
            glider.setPositionDirectly(JXG.COORDS_BY_USER, [x, y]);    // Position the glider
            from = false;
            for (el in this.board.objects) {                         // Update all elements from the glider up to the trace element
                pEl = this.board.objects[el];
                if (pEl==glider) { 
                    from = true;
                }
                if (!from) {
                    continue;
                }
                if (!pEl.needsRegularUpdate) { continue; }
                savetrace = pEl.visProp.trace;                       // Save the trace mode of the element
                pEl.visProp.trace = false;
                pEl.needsUpdate = true;
                pEl.update(true);
                pEl.visProp.trace = savetrace;                       // Restore the trace mode
                if (pEl==tracepoint) { break; }
            }
            this.dataX[i] = tracepoint.X();                          // Store the position of the trace point
            this.dataY[i] = tracepoint.Y();
        }
        glider.position = savePos;                                   // Restore the original position of the glider
        from = false;
        for (el in this.board.objects) {                             // Update all elements from the glider to the trace point
            pEl = this.board.objects[el];
            if (pEl==glider) { 
                from = true;
            }
            if (!from) {
                continue;
            }
            if (!pEl.needsRegularUpdate) { continue; }
            savetrace = pEl.visProp.trace;
            pEl.visProp.trace = false;
            pEl.needsUpdate = true;
            pEl.update(true); //.updateRenderer();
            pEl.visProp.trace = savetrace;
            if (pEl==tracepoint) { 
                break;
            }
        }
    };

    return c;
};

JXG.JSXGraph.registerElement('tracecurve', JXG.createTracecurve);



/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/** 
 * @fileoverview In this file the geometry object Arc is defined. Arc stores all
 * style and functional properties that are required to draw an arc on a board.
 */

/**
 * @class An arc is a segment of the circumference of a circle. It is defined by a center, one point that
 * defines the radius, and a third point that defines the angle of the arc.
 * @pseudo
 * @name Arc
 * @augments Curve
 * @constructor
 * @type JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be an arc of a circle around p1 through p2. The arc is drawn
 * counter-clockwise from p2 to p3.
 * @example
 * // Create an arc out of three free points
 * var p1 = board.create('point', [2.0, 2.0]);
 * var p2 = board.create('point', [1.0, 0.5]);
 * var p3 = board.create('point', [3.5, 1.0]);
 *
 * var a = board.create('arc', [p1, p2, p3]);
 * </pre><div id="114ef584-4a5e-4686-8392-c97501befb5b" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('114ef584-4a5e-4686-8392-c97501befb5b', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [2.0, 2.0]),
 *       p2 = board.create('point', [1.0, 0.5]),
 *       p3 = board.create('point', [3.5, 1.0]),
 *
 *       a = board.create('arc', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
JXG.createArc = function(board, parents, attributes) {
    var el, attr, i;


    // this method is used to create circumccirclearcs, too. if a circumcirclearc is created we get a fourth
    // point, that's why we need to check that case, too.
    if(!(parents = JXG.checkParents('arc', parents, [
            [JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT],
            [JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT]]))) {
        throw new Error("JSXGraph: Can't create Arc with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" +
                        (typeof parents[2]) + "'." +
                        "\nPossible parent types: [point,point,point]");
    }

    attr = JXG.copyAttributes(attributes, board.options, 'arc');
    el = board.create('curve', [[0],[0]], attr);

    el.elType = 'arc';

    el.parents = [];
    for (i = 0; i < parents.length; i++) {
        if (parents[i].id) {
            el.parents.push(parents[i].id);
        }
    }

    /**
     * documented in JXG.GeometryElement
     * @ignore
     */
    el.type = JXG.OBJECT_TYPE_ARC;

    /**
     * Center of the arc.
     * @memberOf Arc.prototype
     * @name center
     * @type JXG.Point
     */
    el.center = JXG.getReference(board, parents[0]);

    /**
     * Point defining the arc's radius.
     * @memberOf Arc.prototype
     * @name radiuspoint
     * @type JXG.Point
     */
    el.radiuspoint = JXG.getReference(board, parents[1]);
    el.point2 = el.radiuspoint;

    /**
     * The point defining the arc's angle.
     * @memberOf Arc.prototype
     * @name anglepoint
     * @type JXG.Point
     */
    el.anglepoint = JXG.getReference(board, parents[2]);
    el.point3 = el.anglepoint;

    // Add arc as child to defining points
    el.center.addChild(el);
    el.radiuspoint.addChild(el);
    el.anglepoint.addChild(el);
    
    /**
     * TODO
     */
    el.useDirection = attr['usedirection'];      // useDirection is necessary for circumCircleArcs

    // documented in JXG.Curve
    el.updateDataArray = function() {
        var A = this.radiuspoint,
            B = this.center,
            C = this.anglepoint,
            beta, co, si, matrix, phi, i,
            x = B.X(),
            y = B.Y(),
            z = B.Z(),
            v, det, p0c, p1c, p2c,
            p1, p2, p3, p4,
            k, ax, ay, bx, by, d, r, sgn = 1.0,
            PI2 = Math.PI*0.5;
            
        phi = JXG.Math.Geometry.rad(A,B,C);
        
        if ((this.visProp.type=='minor' && phi>Math.PI) 
            || (this.visProp.type=='major' && phi<Math.PI)) { 
            phi = 2*Math.PI - phi; 
            sgn = -1.0;
        }

        if (this.useDirection) { // This is true for circumCircleArcs. In that case there is
                                  // a fourth parent element: [center, point1, point3, point2]
            p0c = parents[1].coords.usrCoords;
            p1c = parents[3].coords.usrCoords;
            p2c = parents[2].coords.usrCoords;
            det = (p0c[1]-p2c[1])*(p0c[2]-p1c[2]) - (p0c[2]-p2c[2])*(p0c[1]-p1c[1]);
            if (det < 0) {
                this.radiuspoint = parents[1];
                this.anglepoint = parents[2];
            } else {
                this.radiuspoint = parents[2];
                this.anglepoint = parents[1];
            }
        }

        p1 = [A.Z(), A.X(), A.Y()];
        p4 = p1.slice(0);
        r = B.Dist(A);
        x /= z;
        y /= z;
        this.dataX = [p1[1]/p1[0]];
        this.dataY = [p1[2]/p1[0]];
        while (phi>JXG.Math.eps) {
            if (phi>=PI2) {
                beta = PI2;
                phi -= PI2;
            } else {
                beta = phi;
                phi = 0.0;
            }

            co = Math.cos(sgn*beta);
            si = Math.sin(sgn*beta);
            matrix = [[1,        0,   0],  // z missing
                    [x*(1-co)+y*si,co,-si],
                    [y*(1-co)-x*si,si, co]];
            v = JXG.Math.matVecMult(matrix, p1);
            p4 = [v[0]/v[0], v[1]/v[0], v[2]/v[0]];

            ax = p1[1]-x;
            ay = p1[2]-y;
            bx = p4[1]-x;
            by = p4[2]-y;

            d = Math.sqrt((ax+bx)*(ax+bx) + (ay+by)*(ay+by));
            //if (beta>Math.PI) { d *= -1; }
 
            if (Math.abs(by-ay)>JXG.Math.eps) {
                k = (ax+bx)*(r/d-0.5)/(by-ay)*8.0/3.0;
            } else {
                k = (ay+by)*(r/d-0.5)/(ax-bx)*8.0/3.0;
            }

            p2 = [1, p1[1]-k*ay, p1[2]+k*ax ];
            p3 = [1, p4[1]+k*by, p4[2]-k*bx ];
        
            this.dataX = this.dataX.concat([p2[1], p3[1], p4[1]]);
            this.dataY = this.dataY.concat([p2[2], p3[2], p4[2]]);
            p1 = p4.slice(0);
        }
        this.bezierDegree = 3;

        this.updateStdform();
        this.updateQuadraticform();
    };

    /**
     * Determines the arc's current radius. I.e. the distance between {@link Arc#center} and {@link Arc#radiuspoint}.
     * @memberOf Arc.prototype
     * @name Radius
     * @function
     * @returns {Number} The arc's radius
     */
    el.Radius = function() {
        return this.radiuspoint.Dist(this.center);
    };

    /**
     * @deprecated Use {@link Arc#Radius}
     * @memberOf Arc.prototype
     * @name getRadius
     * @function
     * @returns {Number}
     */
    el.getRadius = function() {
        return this.Radius();
    };

    // documented in geometry element
    el.hasPoint = function (x, y) {
        var prec = this.board.options.precision.hasPoint/(this.board.unitX),
            r = this.Radius(),
            dist, checkPoint,
            has, angle, alpha, beta,
            invMat, c;
            
        checkPoint = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board);
        
        if (this.transformations.length>0) {
            /** 
             * Transform the mouse/touch coordinates 
             * back to the original position of the curve.
             */
            this.updateTransformMatrix();
            invMat = JXG.Math.inverse(this.transformMat);
            c = JXG.Math.matVecMult(invMat, checkPoint.usrCoords);
            checkPoint = new JXG.Coords(JXG.COORDS_BY_USER, c, this.board);
        }
            
        dist = this.center.coords.distance(JXG.COORDS_BY_USER, checkPoint);
        has = (Math.abs(dist-r) < prec);

        /**
         * At that point we know that the user has touched the circle line.
         */
        if (has) {
            angle = JXG.Math.Geometry.rad(this.radiuspoint,this.center,checkPoint.usrCoords.slice(1));
            alpha = 0.0;
            beta = JXG.Math.Geometry.rad(this.radiuspoint,this.center,this.anglepoint);
            if ((this.visProp.type=='minor' && beta>Math.PI)
                || (this.visProp.type=='major' && beta<Math.PI)) { 
                alpha = beta; 
                beta = 2*Math.PI;
            } 
            if (angle<alpha || angle>beta) { 
                has = false; 
            }
        }
        return has;    
    };

    /**
     * Checks whether (x,y) is within the sector defined by the arc.
     * @memberOf Arc.prototype
     * @name hasPointSector
     * @function
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise.
     */
    el.hasPointSector = function (x, y) { 
        var checkPoint = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board),
            r = this.Radius(),
            dist = this.center.coords.distance(JXG.COORDS_BY_USER,checkPoint),
            has = (dist<r),
            angle, alpha, beta;
        
        if (has) {
            angle = JXG.Math.Geometry.rad(this.radiuspoint,this.center,checkPoint.usrCoords.slice(1));
            alpha = 0.0;
            beta = JXG.Math.Geometry.rad(this.radiuspoint,this.center,this.anglepoint);
            if ((this.visProp.type=='minor' && beta>Math.PI) 
                || (this.visProp.type=='major' && beta<Math.PI)) { 
                alpha = beta; 
                beta = 2*Math.PI;
            } 
            if (angle<alpha || angle>beta) { 
                has = false; 
            }
        }
        return has;    
    };

    // documented in geometry element
    el.getTextAnchor = function() {
        return this.center.coords;
    };

    // documented in geometry element
    el.getLabelAnchor = function() {
        var angle,
            dx = 10/(this.board.unitX),
            dy = 10/(this.board.unitY),
            p2c = this.point2.coords.usrCoords,
            pmc = this.center.coords.usrCoords,
            bxminusax = p2c[1] - pmc[1],
            byminusay = p2c[2] - pmc[2],
            coords, vecx, vecy, len;

        if(this.label.content != null) {                          
            this.label.content.relativeCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0,0],this.board);                      
        }  

        angle = JXG.Math.Geometry.rad(this.radiuspoint, this.center, this.anglepoint);
        if ((this.visProp.type=='minor' && angle>Math.PI)
            || (this.visProp.type=='major' && angle<Math.PI)) { 
            angle = -(2*Math.PI - angle); 
        } 
        
        coords = new JXG.Coords(JXG.COORDS_BY_USER, 
                        [pmc[1]+ Math.cos(angle*0.5)*bxminusax - Math.sin(angle*0.5)*byminusay, 
                        pmc[2]+ Math.sin(angle*0.5)*bxminusax + Math.cos(angle*0.5)*byminusay], 
                        this.board);

        vecx = coords.usrCoords[1] - pmc[1];
        vecy = coords.usrCoords[2] - pmc[2];
    
        len = Math.sqrt(vecx*vecx+vecy*vecy);
        vecx = vecx*(len+dx)/len;
        vecy = vecy*(len+dy)/len;

        return new JXG.Coords(JXG.COORDS_BY_USER, [pmc[1]+vecx,pmc[2]+vecy], this.board);
    };
    
    /**
     * TODO description
     */
    el.updateQuadraticform = function () {
        var m = this.center,
            mX = m.X(), mY = m.Y(), r = this.Radius();
        this.quadraticform = [[mX*mX+mY*mY-r*r,-mX,-mY],
            [-mX,1,0],
            [-mY,0,1]
        ];
    };

    /**
     * TODO description
     */
    el.updateStdform = function () {
        this.stdform[3] = 0.5;
        this.stdform[4] = this.Radius();
        this.stdform[1] = -this.center.coords.usrCoords[1];
        this.stdform[2] = -this.center.coords.usrCoords[2];
        this.normalize();
    };

    el.prepareUpdate().update();
    return el;
};

JXG.JSXGraph.registerElement('arc', JXG.createArc);

/**
 * @class A semicircle is a special arc defined by two points. The arc hits both points.
 * @pseudo
 * @name Semicircle
 * @augments Arc
 * @constructor
 * @type Arc
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point} p1,p2 The result will be a composition of an arc drawn clockwise from <tt>p1</tt> and
 * <tt>p2</tt> and the midpoint of <tt>p1</tt> and <tt>p2</tt>.
 * @example
 * // Create an arc out of three free points
 * var p1 = board.create('point', [4.5, 2.0]);
 * var p2 = board.create('point', [1.0, 0.5]);
 *
 * var a = board.create('semicircle', [p1, p2]);
 * </pre><div id="5385d349-75d7-4078-b732-9ae808db1b0e" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('5385d349-75d7-4078-b732-9ae808db1b0e', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [4.5, 2.0]),
 *       p2 = board.create('point', [1.0, 0.5]),
 *
 *       sc = board.create('semicircle', [p1, p2]);
 * })();
 * </script><pre>
 */
JXG.createSemicircle = function(board, parents, attributes) {
    var el, mp, attr;
    

    // we need 2 points
    if ( (JXG.isPoint(parents[0])) && (JXG.isPoint(parents[1])) ) {

        attr = JXG.copyAttributes(attributes, board.options, 'semicircle', 'midpoint');
        mp = board.create('midpoint', [parents[0], parents[1]], attr);

        mp.dump = false;

        attr = JXG.copyAttributes(attributes, board.options, 'semicircle');
        el = board.create('arc', [mp, parents[1], parents[0]], attr);

        el.elType = 'semicircle';
        el.parents = [parents[0].id, parents[1].id];
        el.subs = {
            midpoint: mp
        };

        /**
         * The midpoint of the two defining points.
         * @memberOf Semicircle.prototype
         * @name midpoint
         * @type Midpoint
         */
        el.midpoint = el.center = mp;
    } else
        throw new Error("JSXGraph: Can't create Semicircle with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,point]");

    return el;
};

JXG.JSXGraph.registerElement('semicircle', JXG.createSemicircle);

/**
 * @class A circumcircle arc is an {@link Arc} defined by three points. All three points lie on the arc.
 * @pseudo
 * @name CircumcircleArc
 * @augments Arc
 * @constructor
 * @type Arc
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be a composition of an arc of the circumcircle of
 * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt> and the midpoint of the circumcircle of the three points. The arc is drawn
 * counter-clockwise from <tt>p1</tt> over <tt>p2</tt> to <tt>p3</tt>.
 * @example
 * // Create a circum circle arc out of three free points
 * var p1 = board.create('point', [2.0, 2.0]);
 * var p2 = board.create('point', [1.0, 0.5]);
 * var p3 = board.create('point', [3.5, 1.0]);
 *
 * var a = board.create('arc', [p1, p2, p3]);
 * </pre><div id="87125fd4-823a-41c1-88ef-d1a1369504e3" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('87125fd4-823a-41c1-88ef-d1a1369504e3', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [2.0, 2.0]),
 *       p2 = board.create('point', [1.0, 0.5]),
 *       p3 = board.create('point', [3.5, 1.0]),
 *
 *       cca = board.create('circumcirclearc', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
JXG.createCircumcircleArc = function(board, parents, attributes) {
    var el, mp, attr;
    
    // We need three points
    if ( (JXG.isPoint(parents[0])) && (JXG.isPoint(parents[1])) && (JXG.isPoint(parents[2]))) {

        attr = JXG.copyAttributes(attributes, board.options, 'circumcirclearc', 'center');
        mp = board.create('circumcenter',[parents[0], parents[1], parents[2]], attr);

        mp.dump = false;

        attr = JXG.copyAttributes(attributes, board.options, 'circumcirclearc');
        attr.usedirection = true;
        el = board.create('arc', [mp, parents[0], parents[2], parents[1]], attr);

        el.elType = 'circumcirclearc';
        el.parents = [parents[0].id, parents[1].id, parents[2].id];
        el.subs = {
            center: mp
        };

        /**
         * The midpoint of the circumcircle of the three points defining the circumcircle arc.
         * @memberOf CircumcircleArc.prototype
         * @name center
         * @type Circumcenter
         */
        el.center = mp;
    } else
        throw new Error("JSXGraph: create Circumcircle Arc with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
                        "\nPossible parent types: [point,point,point]");

    return el;
};

JXG.JSXGraph.registerElement('circumcirclearc', JXG.createCircumcircleArc);

/**
 * @class A minor arc is a segment of the circumference of a circle having measure less than or equal to 
 * 180 degrees (pi radians). It is defined by a center, one point that
 * defines the radius, and a third point that defines the angle of the arc.
 * @pseudo
 * @name MinorArc
 * @augments Curve
 * @constructor
 * @type JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor arc is an arc of a circle around p1 having measure less than or equal to 
 * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. 
 * @example
 * // Create an arc out of three free points
 * var p1 = board.create('point', [2.0, 2.0]);
 * var p2 = board.create('point', [1.0, 0.5]);
 * var p3 = board.create('point', [3.5, 1.0]);
 *
 * var a = board.create('arc', [p1, p2, p3]);
 * </pre><div id="af27ddcc-265f-428f-90dd-d31ace945800" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('af27ddcc-265f-428f-90dd-d31ace945800', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [2.0, 2.0]),
 *       p2 = board.create('point', [1.0, 0.5]),
 *       p3 = board.create('point', [3.5, 1.0]),
 *
 *       a = board.create('minorarc', [p1, p2, p3]);
 * })();
 * </script><pre>
 */

JXG.createMinorArc = function(board, parents, attributes) {
    attributes.type = 'minor';
    return JXG.createArc(board, parents, attributes);
};

JXG.JSXGraph.registerElement('minorarc', JXG.createMinorArc);

/**
 * @class A major arc is a segment of the circumference of a circle having measure greater than or equal to 
 * 180 degrees (pi radians). It is defined by a center, one point that
 * defines the radius, and a third point that defines the angle of the arc.
 * @pseudo
 * @name MinorArc
 * @augments Curve
 * @constructor
 * @type JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major arc is an arc of a circle around p1 having measure greater than or equal to 
 * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. 
 * @example
 * // Create an arc out of three free points
 * var p1 = board.create('point', [2.0, 2.0]);
 * var p2 = board.create('point', [1.0, 0.5]);
 * var p3 = board.create('point', [3.5, 1.0]);
 *
 * var a = board.create('arc', [p1, p2, p3]);
 * </pre><div id="83c6561f-7561-4047-b98d-036248a00932" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('83c6561f-7561-4047-b98d-036248a00932', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *       p1 = board.create('point', [2.0, 2.0]),
 *       p2 = board.create('point', [1.0, 0.5]),
 *       p3 = board.create('point', [3.5, 1.0]),
 *
 *       a = board.create('majorarc', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
JXG.createMajorArc = function(board, parents, attributes) {
    attributes.type = 'major';
    return JXG.createArc(board, parents, attributes);
};

JXG.JSXGraph.registerElement('majorarc', JXG.createMajorArc);



/*    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.

*/

/**
 * @class A circular sector is a subarea of the area enclosed by a circle. It is enclosed by two radii and an arc.
 * @pseudo
 * @name Sector
 * @augments JXG.Curve
 * @constructor
 * @type JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 A sector is defined by three points: The sector's center <tt>p1</tt>,
 * a second point <tt>p2</tt> defining the radius and a third point <tt>p3</tt> defining the angle of the sector. The
 * Sector is always drawn counter clockwise from <tt>p2</tt> to <tt>p3</tt>
 * @example
 * // Create an arc out of three free points
 * var p1 = board.create('point', [1.5, 5.0]),
 *     p2 = board.create('point', [1.0, 0.5]),
 *     p3 = board.create('point', [5.0, 3.0]),
 *
 *     a = board.create('sector', [p1, p2, p3]);
 * </pre><div id="49f59123-f013-4681-bfd9-338b89893156" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('49f59123-f013-4681-bfd9-338b89893156', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *     p1 = board.create('point', [1.5, 5.0]),
 *     p2 = board.create('point', [1.0, 0.5]),
 *     p3 = board.create('point', [5.0, 3.0]),
 *
 *     a = board.create('sector', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
JXG.createSector = function(board, parents, attributes) {
    var el, attr;
        
    // Three points?
    if ( !(JXG.isPoint(parents[0]) && JXG.isPoint(parents[1]) && JXG.isPoint(parents[2]))) {
        throw new Error("JSXGraph: Can't create Sector with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + 
                        (typeof parents[2]) + "'.");
    }

    attr = JXG.copyAttributes(attributes, board.options, 'sector');

    el = board.create('curve', [[0], [0]], attr);
    
    el.type = JXG.OBJECT_TYPE_SECTOR;

    el.elType = 'sector';
    el.parents = [parents[0].id, parents[1].id, parents[2].id];

    /**
     * Midpoint of the sector.
     * @memberOf Sector.prototype
     * @name point1
     * @type JXG.Point
     */
    el.point1 = JXG.getReference(board, parents[0]);
    el.center = el.point1;

    /**
     * This point together with {@link Sector#point1} defines the radius..
     * @memberOf Sector.prototype
     * @name point2
     * @type JXG.Point
     */
    el.point2 = JXG.getReference(board, parents[1]);
    el.radiuspoint = el.point2;

    /**
     * Defines the sector's angle.
     * @memberOf Sector.prototype
     * @name point3
     * @type JXG.Point
     */
    el.point3 = JXG.getReference(board, parents[2]);
    el.anglepoint = el.point3;
    
    /* Add arc as child to defining points */
    el.point1.addChild(el);
    el.point2.addChild(el);
    el.point3.addChild(el);
    
    el.useDirection = attributes['usedirection'];      // useDirection is necessary for circumCircleSectors

    /**
     * documented in JXG.Curve
     * @ignore
     */
    el.updateDataArray = function() {
        var A = this.point2,
            B = this.point1,
            C = this.point3,
            beta, co, si, matrix,
            phi = JXG.Math.Geometry.rad(A,B,C),
            i,
            x = B.X(),
            y = B.Y(),
            z = B.Z(),
            v, 
            det, p0c, p1c, p2c,
            p1, p2, p3, p4,
            k, ax, ay, bx, by, d, r,
            PI2 = Math.PI*0.5;

        if (this.useDirection) {  // This is true for circumCircleArcs. In that case there is
                                  // a fourth parent element: [midpoint, point1, point3, point2]
            p0c = parents[1].coords.usrCoords,
            p1c = parents[3].coords.usrCoords,
            p2c = parents[2].coords.usrCoords;
            det = (p0c[1]-p2c[1])*(p0c[2]-p1c[2]) - (p0c[2]-p2c[2])*(p0c[1]-p1c[1]);
            if(det < 0) {
                this.point2 = parents[1];
                this.point3 = parents[2];
            }
            else {
                this.point2 = parents[2];
                this.point3 = parents[1];
            }
        }
        
        r = B.Dist(A);
        p1 = [A.Z(), A.X(), A.Y()];
        p1[1] /= p1[0];
        p1[2] /= p1[0];
        p1[0] /= p1[0];
        p4 = p1.slice(0);
        x /= z;
        y /= z;
        this.dataX = [x, x+0.333*(p1[1]-x), x+0.666*(p1[1]-x), p1[1]];
        this.dataY = [y, y+0.333*(p1[2]-y), y+0.666*(p1[2]-y), p1[2]];
        while (phi>JXG.Math.eps) {
            if (phi>=PI2) {
                beta = PI2;
                phi -= PI2;
            } else {
                beta = phi;
                phi = 0.0;
            }

            co = Math.cos(beta);
            si = Math.sin(beta);
            matrix = [[1,          0,   0],
                    [x*(1-co)+y*si,co,-si],
                    [y*(1-co)-x*si,si, co]];
            v = JXG.Math.matVecMult(matrix, p1);
            p4 = [v[0]/v[0], v[1]/v[0], v[2]/v[0]];

            ax = p1[1]-x;
            ay = p1[2]-y;
            bx = p4[1]-x;
            by = p4[2]-y;

            d = Math.sqrt((ax+bx)*(ax+bx) + (ay+by)*(ay+by));
            //if (beta>Math.PI) { d *= -1; }
 
            if (Math.abs(by-ay)>JXG.Math.eps) {
                k = (ax+bx)*(r/d-0.5)/(by-ay)*8.0/3.0;
            } else {
                k = (ay+by)*(r/d-0.5)/(ax-bx)*8.0/3.0;
            }

            p2 = [1, p1[1]-k*ay, p1[2]+k*ax ];
            p3 = [1, p4[1]+k*by, p4[2]-k*bx ];
        
            this.dataX = this.dataX.concat([p2[1], p3[1], p4[1]]);
            this.dataY = this.dataY.concat([p2[2], p3[2], p4[2]]);
            p1 = p4.slice(0);
        }
        this.dataX = this.dataX.concat([ p4[1]+0.333*(x-p4[1]), p4[1]+0.666*(x-p4[1]), x]);
        this.dataY = this.dataY.concat([ p4[2]+0.333*(y-p4[2]), p4[2]+0.666*(y-p4[2]), y]);
        
        this.bezierDegree = 3;
    };

    /**
     * Returns the radius of the sector.
     * @memberOf Sector.prototype
     * @name Radius
     * @function
     * @returns {Number} The distance between {@link Sector#point1} and {@link Sector#point2}.
     */
    el.Radius = function() {
        return this.point2.Dist(this.point1);
    };

    /**
     * deprecated
     * @ignore
     */
    el.getRadius = function() {
        return this.Radius();
    };

    // documented in geometry element
    el.hasPoint = function (x, y) {
        var prec = this.board.options.precision.hasPoint/(this.board.unitX),
            checkPoint = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board),
            r = this.Radius(),
            dist = this.center.coords.distance(JXG.COORDS_BY_USER, checkPoint),
            has = (Math.abs(dist-r) < prec),
            angle, alpha, beta;
            
        if (has) {
            angle = JXG.Math.Geometry.rad(this.point2, this.center, checkPoint.usrCoords.slice(1));
            alpha = 0.0;
            beta = JXG.Math.Geometry.rad(this.point2, this.center, this.point3);
            if (angle<alpha || angle>beta) { 
                has = false; 
            }
        }
        return has;    
    };

    /**
     * Checks whether (x,y) is within the area defined by the sector.
     * @memberOf Sector.prototype
     * @name hasPointSector
     * @function
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise.
     */
    el.hasPointSector = function (x, y) { 
        var checkPoint = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board),
            r = this.Radius(),
            dist = this.point1.coords.distance(JXG.COORDS_BY_USER,checkPoint),
            has = (dist<r),
            angle;
        
        if(has) {
            angle = JXG.Math.Geometry.rad(this.point2,this.point1,checkPoint.usrCoords.slice(1));
            if (angle>JXG.Math.Geometry.rad(this.point2,this.point1,this.point3)) { has = false; }
        }
        return has;    
    };

    /**
     * documented in GeometryElement
     * @ignore
     */
    el.getTextAnchor = function() {
        return this.point1.coords;
    };

    /**
     * documented in GeometryElement
     * @ignore
     */
    el.getLabelAnchor = function() {
        var angle = JXG.Math.Geometry.rad(this.point2, this.point1, this.point3),
            dx = 13/(this.board.unitX),
            dy = 13/(this.board.unitY),
            p2c = this.point2.coords.usrCoords,
            pmc = this.point1.coords.usrCoords,
            bxminusax = p2c[1] - pmc[1],
            byminusay = p2c[2] - pmc[2],
            coords, vecx, vecy, len;

        if(this.label.content != null) {                          
            this.label.content.relativeCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0,0],this.board);                      
        }  

        coords = new JXG.Coords(JXG.COORDS_BY_USER, 
                        [pmc[1]+ Math.cos(angle*0.5)*bxminusax - Math.sin(angle*0.5)*byminusay, 
                        pmc[2]+ Math.sin(angle*0.5)*bxminusax + Math.cos(angle*0.5)*byminusay], 
                        this.board);

        vecx = coords.usrCoords[1] - pmc[1];
        vecy = coords.usrCoords[2] - pmc[2];
    
        len = Math.sqrt(vecx*vecx+vecy*vecy);
        vecx = vecx*(len+dx)/len;
        vecy = vecy*(len+dy)/len;

        return new JXG.Coords(JXG.COORDS_BY_USER, [pmc[1]+vecx,pmc[2]+vecy],this.board);
    };

    el.prepareUpdate().update();
    
    return el;
};

JXG.JSXGraph.registerElement('sector', JXG.createSector);


/**
 * @class A circumcircle sector is different from a {@link Sector} mostly in the way the parent elements are interpreted.
 * At first, the circum centre is determined from the three given points. Then the sector is drawn from <tt>p1</tt> through
 * <tt>p2</tt> to <tt>p3</tt>.
 * @pseudo
 * @name Circumcirclesector
 * @augments Sector
 * @constructor
 * @type Sector
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 A circumcircle sector is defined by the circumcircle which is determined
 * by these three given points. The circumcircle sector is always drawn from <tt>p1</tt> through <tt>p2</tt> to <tt>p3</tt>.
 * @example
 * // Create an arc out of three free points
 * var p1 = board.create('point', [1.5, 5.0]),
 *     p2 = board.create('point', [1.0, 0.5]),
 *     p3 = board.create('point', [5.0, 3.0]),
 *
 *     a = board.create('circumcirclesector', [p1, p2, p3]);
 * </pre><div id="695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *     p1 = board.create('point', [1.5, 5.0]),
 *     p2 = board.create('point', [1.0, 0.5]),
 *     p3 = board.create('point', [5.0, 3.0]),
 *
 *     a = board.create('circumcirclesector', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
 JXG.createCircumcircleSector = function(board, parents, attributes) {
    var el, mp, attr;
    
    if ( (JXG.isPoint(parents[0])) && (JXG.isPoint(parents[1])) && (JXG.isPoint(parents[2]))) {
        attr = JXG.copyAttributes(attributes, board.options, 'circumcirclesector', 'center');
        mp = board.create('circumcenter',[parents[0], parents[1], parents[2]], attr);

        mp.dump = false;

        attr = JXG.copyAttributes(attributes, board.options, 'circumcirclesector');
        el = board.create('sector', [mp,parents[0],parents[2],parents[1]], attr);

        el.elType = 'circumcirclesector';
        el.parents = [parents[0].id, parents[1].id, parents[2].id];

        /**
         * Center of the circumcirclesector
         * @memberOf CircumcircleSector.prototype
         * @name center
         * @type Circumcenter
         */
        el.center = mp;
        el.subs = {
            center: mp
        }
    } else {
        throw new Error("JSXGraph: Can't create circumcircle sector with parent types '" + 
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'.");
    }

    return el;
};

JXG.JSXGraph.registerElement('circumcirclesector', JXG.createCircumcircleSector);


/**
 * @class The angle element is used to denote an angle defined by three points. Visually it is just a {@link Sector}
 * element with a radius not defined by the parent elements but by an attribute <tt>radius</tt>. As opposed to the sector,
 * an angle has two angle points and no radius point.
 * Sector is displayed if type=="sector".
 * If type=="square", instead of a sector a parallelogram is displayed. 
 * In case of type=="auto", a square is displayed if the angle is near orthogonal. 
 * If no name is provided the angle label is automatically set to a lower greek letter.
 * @pseudo
 * @name Angle
 * @augments Sector
 * @constructor
 * @type Sector
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 An angle is always drawn counterclockwise from <tt>p1</tt> to
 * <tt>p3</tt> around <tt>p2</tt>.
 * @example
 * // Create an arc out of three free points
 * var p1 = board.create('point', [5.0, 3.0]),
 *     p2 = board.create('point', [1.0, 0.5]),
 *     p3 = board.create('point', [1.5, 5.0]),
 *
 *     a = board.create('angle', [p1, p2, p3]);
 * </pre><div id="a34151f9-bb26-480a-8d6e-9b8cbf789ae5" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('a34151f9-bb26-480a-8d6e-9b8cbf789ae5', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 *     p1 = board.create('point', [5.0, 3.0]),
 *     p2 = board.create('point', [1.0, 0.5]),
 *     p3 = board.create('point', [1.5, 5.0]),
 *
 *     a = board.create('angle', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
JXG.createAngle = function(board, parents, attributes) {
    var el, p, q, text, attr, attrsub, i, dot;

    // Test if three points are given
    if ( (JXG.isPoint(parents[0])) && (JXG.isPoint(parents[1])) && (JXG.isPoint(parents[2]))) {
        attr = JXG.copyAttributes(attributes, board.options, 'angle');
        //  If empty, create a new name
        text = attr.name;
        if (typeof text =='undefined' || text == '') {
            text = board.generateName({type:JXG.OBJECT_TYPE_ANGLE});
            attr.name = text;
        }
        
        attrsub = JXG.copyAttributes(attributes, board.options, 'angle', 'radiuspoint');

        // Helper point: radius point
        // Start with dummy values until the sector has been created.
        p = board.create('point', [0,1,0], attrsub);
        
        p.dump = false;

        attrsub = JXG.copyAttributes(attributes, board.options, 'angle', 'pointsquare');

        // Second helper point for square
        // Start with dummy values until the sector has been created.
        q = board.create('point', [0,1,1], attrsub);
        q.dump = false;

        // Sector is just a curve with its own updateDataArray method
        el = board.create('sector', [parents[1], p, parents[2]], attr);

        el.elType = 'angle';
        el.parents = [parents[0].id, parents[1].id, parents[2].id];
        el.subs = {
            point: p,
            pointsquare: q
        };

        el.updateDataArraySquare = function() {
            var S = parents[1],
                v, l1, l2, r;
                   
            v = JXG.Math.crossProduct(q.coords.usrCoords, S.coords.usrCoords);
            l1 = [-p.X()*v[1]-p.Y()*v[2], p.Z()*v[1], p.Z()*v[2]];
            v = JXG.Math.crossProduct(p.coords.usrCoords, S.coords.usrCoords);
            l2 = [-q.X()*v[1]-q.Y()*v[2], q.Z()*v[1], q.Z()*v[2]];
            r = JXG.Math.crossProduct(l1,l2);
            r[1] /= r[0];
            r[2] /= r[0];
            
            this.dataX = [S.X(), p.X(), r[1], q.X(), S.X()];
            this.dataY = [S.Y(), p.Y(), r[2], q.Y(), S.Y()];
            this.bezierDegree = 1;
        };

        el.updateDataArrayNone = function() {
            this.dataX = [NaN];
            this.dataY = [NaN];
            this.bezierDegree = 1;
        };
        
        el.updateDataArraySector = el.updateDataArray;
        el.updateDataArray = function() {
            var type = this.visProp.type,
                deg = JXG.Math.Geometry.trueAngle(parents[0], parents[1], parents[2]);
                
            if (Math.abs(deg-90.0)<this.visProp.orthosensitivity) {
                type = this.visProp.orthotype;
            }

            if (type=='none') {
                this.updateDataArrayNone();
            } else if (type==='square') {
                this.updateDataArraySquare();
            } else if (type==='sector') {
                this.updateDataArraySector();
            } else if (type==='sectordot') {
                this.updateDataArraySector();
                if (this.dot.visProp.visible === false) {
                    this.dot.setProperty({visible: true});
                }
            }
            
            if (type!=='sectordot' && this.dot.visProp.visible === true) {
                    this.dot.setProperty({visible: false});
            }
        };

        /* 
         * Supply the helper points with the correct function, which depends
         * on the visProp.radius property of the sector.
         * With this trick, setPropertyy({radius:...}) works.
         */
        p.addConstraint([function(){
                var A = parents[0], S = parents[1],
                    r = JXG.evaluate(el.visProp.radius),
                    d = S.Dist(A);
                return [S.X()+(A.X()-S.X())*r/d, S.Y()+(A.Y()-S.Y())*r/d];
            }]);
        q.addConstraint([function(){
                var A = parents[2], S = parents[1],
                    r = JXG.evaluate(el.visProp.radius),
                    d = S.Dist(A);
                return [S.X()+(A.X()-S.X())*r/d, S.Y()+(A.Y()-S.Y())*r/d];
            }]);
            
        /**
         * The point defining the radius of the angle element.
         * @type JXG.Point
         * @name radiuspoint
         * @memberOf Angle.prototype
         */
        el.radiuspoint = p;

        /**
         * The point defining the radius of the angle element. Alias for {@link Angle.prototype#radiuspoint}.
         * @type JXG.Point
         * @name point
         * @memberOf Angle.prototype
         */
        el.point = p;

        /**
         * Helper point for angles of type 'square'.
         * @type JXG.Point
         * @name pointsquare
         * @memberOf Angle.prototype
         */
        el.pointsquare = q;

        dot = JXG.copyAttributes(attributes, board.options, 'angle', 'dot');
        /**
         * Indicates a right angle. Invisible by default, use <tt>dot.visible: true</tt> to show.
         * Though this dot indicates a right angle, it can be visible even if the angle is not a right
         * one.
         * @type JXG.Point
         * @name dot
         * @memberOf Angle.prototype
         */
        el.dot = board.create('point', [function () {
            if (JXG.exists(el.dot) && el.dot.visProp.visible === false) {
                return [0, 0];
            }
            
            /*
            transform = board.create('transform', [-parents[1].X(), -parents[1].Y()], {type: 'translate'});
            transform.melt(board.create('transform', [0.5, 0.5], {type: 'scale'}));
            transform.melt(board.create('transform', [JXG.Math.Geometry.rad(parents[0], parents[1], parents[2])/2, 0, 0], {type:'rotate'}));
            transform.melt(board.create('transform', [parents[1].X(), parents[1].Y()], {type: 'translate'}));
            transform.update();
            */
            var c = p.coords.usrCoords,
                a2 = JXG.Math.Geometry.rad(parents[0], parents[1], parents[2])*0.5,
                x = parents[1].X(),
                y = parents[1].Y(),
                mat = [ [1, 0, 0],
                        [x-0.5*x*Math.cos(a2)+0.5*y*Math.sin(a2), Math.cos(a2)*0.5, -Math.sin(a2)*0.5],
                        [y-0.5*x*Math.sin(a2)-0.5*y*Math.cos(a2), Math.sin(a2)*0.5,  Math.cos(a2)*0.5]];
                        
                return JXG.Math.matVecMult(mat, c);
        }], dot);

        el.dot.dump = false;
        el.subs.dot = el.dot;

        for (i = 0; i < 3; i++) {
            JXG.getRef(board,parents[i]).addChild(p);
            JXG.getRef(board,parents[i]).addChild(el.dot);
        }

        el.type = JXG.OBJECT_TYPE_ANGLE;
        JXG.getRef(board,parents[0]).addChild(el);

        // Determine the midpoint of the angle sector line.
        el.rot = board.create('transform', 
            [ function(){ return 0.5*JXG.Math.Geometry.rad(el.point2, el.point1, el.point3);}, el.point1], 
            {type:'rotate'} );

        // documented in GeometryElement
        el.getLabelAnchor = function() {
            var dx = 12,
                dy = 12,
                pmc = this.point1.coords.usrCoords,
                vecx, vecy, len,
                vec;

            if(this.label.content != null) {
                this.label.content.relativeCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0,0], this.board);
            }

            if (JXG.exists(this.visProp.label.fontSize)) {
                dx = this.visProp.label.fontSize;
                dy = this.visProp.label.fontSize;
            } 
            dx /= this.board.unitX;
            dy /= this.board.unitY;

            this.rot.update();
            vec = JXG.Math.matVecMult(this.rot.matrix, this.point2.coords.usrCoords);
            vecx = vec[1] - pmc[1];
            vecy = vec[2] - pmc[2];
            len = Math.sqrt(vecx*vecx+vecy*vecy);
            vecx = vecx*(len+dx)/len;
            vecy = vecy*(len+dy)/len;
            return new JXG.Coords(JXG.COORDS_BY_USER, [pmc[1]+vecx, pmc[2]+vecy], this.board);
        };

        el.Value = function () {
            return JXG.Math.Geometry.rad(this.point2, this.point1, this.point3);
        };

        el.methodMap = JXG.deepCopy(el.methodMap, {
            Value: 'Value'
        });

    } else {
        throw new Error("JSXGraph: Can't create angle with parent types '" +
                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'.");
    }

    /**
     * Set an angle to a prescribed value given in radians. This is only possible if the third point of the angle, i.e.
     * the anglepoint is a free point.
     * @name setAngle
     * @function
     * @param {Number|Function} val Number or Function which returns the size of the angle in Radians
     * @returns {Object} Pointer to the angle element..
     * 
     */
    el.setAngle = function(val) {
        var p, q, t;
        p = this.anglepoint;
        q = this.radiuspoint;
        
        if (p.draggable()) {
            t = this.board.create('transform', [val, this.center], {type:'rotate'});
            p.addTransform(q, t);
            p.isDraggable = false;
            p.parents = [q];
        } 
        return this;
    };
    
    /**
     * Frees an angle from a prescribed value. This is only relevant if the angle size has been set by 
     * setAngle() previously. The anglepoint is set to a free point.
     * @name free
     * @function
     * @returns {Object} Pointer to the angle element..
     * 
     */
    el.free = function() {
        var p = this.anglepoint;
        if (p.transformations.length>0) {
            p.transformations.pop();
            p.isDraggable = true;
            p.parents = [];
        }
        return this;
    };
    
    return el;
};

JXG.JSXGraph.registerElement('angle', JXG.createAngle);


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together
 * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here
 * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the
 * following compositions can be found: <ul>
 *   <li>{@link Arrowparallel} (currently private)</li>
 *   <li>{@link Bisector}</li>
 *   <li>{@link Circumcircle}</li>
 *   <li>{@link Circumcirclemidpoint}</li>
 *   <li>{@link Integral}</li>
 *   <li>{@link Midpoint}</li>
 *   <li>{@link Mirrorpoint}</li>
 *   <li>{@link Normal}</li>
 *   <li>{@link Orthogonalprojection}</li>
 *   <li>{@link Parallel}</li>
 *   <li>{@link Perpendicular}</li>
 *   <li>{@link Perpendicularpoint}</li>
 *   <li>{@link Perpendicularsegment}</li>
 *   <li>{@link Reflection}</li></ul>
 */


/**
 * A composition is a simple container that manages none or more {@link JXG.GeometryElement}s.
 * @param {Object} elements A list of elements with a descriptive name for the element as the key and a reference
 * to the element as the value of every list entry. The name is used to access the element later on.
 * @example
 * var p1 = board.create('point', [1, 2]),
 *     p2 = board.create('point', [2, 3]),
 *     c = new JXG.Composition({
 *         start: p1,
 *         end: p2
 *     });
 *
 * // moves p1 to [3, 3]
 * c.start.moveTo([3, 3]);
 * @class JXG.Composition
 */
JXG.Composition = function (elements) {
    var genericMethods = [
            /**
             * Invokes setProperty for every stored element with a setProperty method and hands over the given arguments.
             * See {@link JXG.GeometryElement#setProperty} for further description, valid parameters and return values.
             * @name setProperty
             * @memberOf JXG.Composition.prototype
             * @function
             */
            'setProperty',

            /**
             * Invokes prepareUpdate for every stored element with a prepareUpdate method and hands over the given arguments.
             * See {@link JXG.GeometryElement#prepareUpdate} for further description, valid parameters and return values.
             * @name prepareUpdate
             * @memberOf JXG.Composition.prototype
             * @function
             */
            'prepareUpdate',

            /**
             * Invokes updateRenderer for every stored element with a updateRenderer method and hands over the given arguments.
             * See {@link JXG.GeometryElement#updateRenderer} for further description, valid parameters and return values.
             * @name updateRenderer
             * @memberOf JXG.Composition.prototype
             * @function
             */
            'updateRenderer',

            /**
             * Invokes update for every stored element with a update method and hands over the given arguments.
             * See {@link JXG.GeometryElement#update} for further description, valid parameters and return values.
             * @name update
             * @memberOf JXG.Composition.prototype
             * @function
             */
            'update',

            /**
             * Invokes highlight for every stored element with a highlight method and hands over the given arguments.
             * See {@link JXG.GeometryElement#highlight} for further description, valid parameters and return values.
             * @name highlight
             * @memberOf JXG.Composition.prototype
             * @function
             */
            'highlight',

            /**
             * Invokes noHighlight for every stored element with a noHighlight method and hands over the given arguments.
             * See {@link JXG.GeometryElement#noHighlight} for further description, valid parameters and return values.
             * @name noHighlight
             * @memberOf JXG.Composition.prototype
             * @function
             */
            'noHighlight'
        ],
        generateMethod = function (what) {
            return function () {
                var i;

                for (i in that.elements) {
                    if (JXG.exists(that.elements[i][what])) {
                        that.elements[i][what].apply(that.elements[i], arguments);
                    }
                }
                return that;
            };
        },
        that = this,
        e;

    for (e = 0; e < genericMethods.length; e++) {
        this[genericMethods[e]] = generateMethod(genericMethods[e]);
    }

    this.elements = {};
    for (e in elements) {
        if (elements.hasOwnProperty(e)) {
            this.add(e, elements[e]);
        }
    }

    this.dump = true;
    this.subs = {};
};

JXG.extend(JXG.Composition.prototype, /** @lends JXG.Composition.prototype */ {

    /**
     * Adds an element to the composition container.
     * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to
     * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate,
     * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in
     * JavaScript.
     * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be
     * another composition, too.
     * @returns {Boolean} True, if the element was added successfully. Reasons why adding the element failed include
     * using a reserved name and providing an invalid element.
     */
    add: function (what, element) {
        if (!JXG.exists(this[what]) && JXG.exists(element)) {
            if (JXG.exists(element.id)) {
                this.elements[element.id] = element;
            } else {
                this.elements[what] = element;
            }
            this[what] = element;

            return true
        }

        return false;
    },

    /**
     * Remove an element from the composition container.
     * @param {String} what The name used to access the element.
     * @returns {Boolean} True, if the element has been removed successfully.
     */
    remove: function (what) {
        var found = false,
            e;

        for (e in this.elements) {
            if (this.elements[e].id === this[what].id) {
                found = true;
                break;
            }
        }

        if (found) {
            delete this.elements[this[what].id];
            delete this[what];
        }

        return found;
    },

    getParents: function () {
        return this.parents;
    },

    getType: function () {
        return this.elType;
    },

    getAttributes: function () {
        var attr = {},
            e;

        for (e in this.subs) {
            attr[e] = this.subs[e].visProp;
        }

        return this.attr;
    }
});

/**
 * @class This is used to construct a point that is the orthogonal projection of a point to a line.
 * @pseudo
 * @description An orthogonal projection is given by a point and a line. It is determined by projecting the given point
 * orthogonal onto the given line.
 * @constructor
 * @name Orthogonalprojection
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
 * @example
 * var p1 = board.create('point', [0.0, 4.0]);
 * var p2 = board.create('point', [6.0, 1.0]);
 * var l1 = board.create('line', [p1, p2]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var pp1 = board.create('orthogonalprojection', [p3, l1]);
 * </pre><div id="7708b215-39fa-41b6-b972-19d73d77d791" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var ppex1_board = JXG.JSXGraph.initBoard('7708b215-39fa-41b6-b972-19d73d77d791', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
 *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
 *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
 *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
 *   var ppex1_pp1 = ppex1_board.create('orthogonalprojection', [ppex1_p3, ppex1_l1]);
 * </script><pre>
 */
JXG.createOrthogonalProjection = function(board, parents, attributes) {
    var l, p, t, atts;

    if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
        p = parents[0];
        l = parents[1];
    }
    else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
        p = parents[1];
        l = parents[0];
    }
    else {
        throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,line]");
    }

    attr = JXG.copyAttributes(attributes, board.options, 'orthogonalprojection');
    t = board.create('point', [function () { return JXG.Math.Geometry.projectPointToLine(p, l, board); }], attributes);
    //t.type = JXG.OBJECT_TYPE_OPROJECT;
    p.addChild(t);
    l.addChild(t);

    t.elType = 'orthogonalprojection';
    t.parents = [p.id, t.id];

    t.update();

    t.generatePolynomial = function() {
        /*
         *  Perpendicular takes point P and line L and creates point T and line M:
         *
         *                          | M
         *                          |
         *                          x P (p1,p2)
         *                          |
         *                          |
         *  L                       |
         *  ----------x-------------x------------------------x--------
         *            A (a1,a2)     |T (t1,t2)               B (b1,b2)
         *                          |
         *                          |
         *
         * So we have two conditions:
         *
         *   (a)  AT  || TB          (collinearity condition)
         *   (b)  PT _|_ AB          (orthogonality condition)
         *
         *      a2-t2       t2-b2
         *     -------  =  -------           (1)
         *      a1-t1       t1-b1
         *
         *      p2-t2         a1-b1
         *     -------  =  - -------         (2)
         *      p1-t1         a2-b2
         *
         * Multiplying (1) and (2) with denominators and simplifying gives
         *
         *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                  (1')
         *
         *    p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0    (2')
         *
         */

        var a1 = l.point1.symbolic.x;
        var a2 = l.point1.symbolic.y;
        var b1 = l.point2.symbolic.x;
        var b2 = l.point2.symbolic.y;

        var p1 = p.symbolic.x;
        var p2 = p.symbolic.y;
        var t1 = t.symbolic.x;
        var t2 = t.symbolic.y;

        var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
        var poly2 = '('+p2+')*('+a2+')-('+p2+')*('+b2+')-('+t2+')*('+a2+')+('+t2+')*('+b2+')+('+p1+')*('+a1+')-('+p1+')*('+b1+')-('+t1+')*('+a1+')+('+t1+')*('+b1+')';

        return [poly1, poly2];
    };

    return t;
};


/**

 * @class This element is used to provide a constructor for a perpendicular.
 * @pseudo
 * @description  A perpendicular is a composition of two elements: a line and a point. The line is orthogonal
 * to a given line and contains a given point.
 * @name Perpendicular
 * @constructor
 * @type JXG.Line
 * @augments Segment
 * @return A {@link JXG.Line} object through the given point that is orthogonal to the given line.
 * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and
 * will contain p.
 * @example
 * // Create a perpendicular
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var l1 = board.create('line', [p1, p2]);
 *
 * var p3 = board.create('point', [3.0, 3.0]);
 * var perp1 = board.create('perpendicular', [l1, p3]);
 * </pre><div id="d5b78842-7b27-4d37-b608-d02519e6cd03" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var pex1_board = JXG.JSXGraph.initBoard('d5b78842-7b27-4d37-b608-d02519e6cd03', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);
 *   var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);
 *   var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);
 *   var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);
 *   var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]);
 * </script><pre>
 */
JXG.createPerpendicular = function(board, parents, attributes) {
    var p, l, pd, attr;

    parents[0] = JXG.getReference(board, parents[0]);
    parents[1] = JXG.getReference(board, parents[1]);

    if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
        l = parents[1];
        p = parents[0];
    }
    else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
        l = parents[0];
        p = parents[1];
    } else {
        throw new Error("JSXGraph: Can't create perpendicular with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [line,point]");
    }

    attr = JXG.copyAttributes(attributes, board.options, 'perpendicular');
    pd = JXG.createLine(board, [
                    function(){ return  l.stdform[2]*p.X()-l.stdform[1]*p.Y();},
                    function(){ return -l.stdform[2]*p.Z();},
                    function(){ return  l.stdform[1]*p.Z();}
                ],
                attr);

    pd.elType = 'perpendicular';
    pd.parents = [l.id, p.id];

    return pd;
};

/**
 * @class This is used to construct a perpendicular point.
 * @pseudo
 * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point
 * orthogonal onto the given line. This used in GEONExTReader only. All other applications should use
 * orthogonal projection.
 * @constructor
 * @name Perpendicularpoint
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
 * @example
 * var p1 = board.create('point', [0.0, 4.0]);
 * var p2 = board.create('point', [6.0, 1.0]);
 * var l1 = board.create('line', [p1, p2]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var pp1 = board.create('perpendicularpoint', [p3, l1]);
 * </pre><div id="ded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var ppex1_board = JXG.JSXGraph.initBoard('ded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
 *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
 *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
 *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
 *   var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]);
 * </script><pre>
 */
JXG.createPerpendicularPoint = function(board, parents, attributes) {
    var l, p, t;

    if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
        p = parents[0];
        l = parents[1];
    }
    else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
        p = parents[1];
        l = parents[0];
    }
    else {
        throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,line]");
    }

    t = board.create('point', [function () { return JXG.Math.Geometry.perpendicular(l, p, board)[0]; }], attributes);
    p.addChild(t);
    l.addChild(t);

    t.elType = 'perpendicularpoint';
    t.parents = [p.id, l.id];

    t.update();

    t.generatePolynomial = function() {
        /*
         *  Perpendicular takes point P and line L and creates point T and line M:
         *
         *                          | M
         *                          |
         *                          x P (p1,p2)
         *                          |
         *                          |
         *  L                       |
         *  ----------x-------------x------------------------x--------
         *            A (a1,a2)     |T (t1,t2)               B (b1,b2)
         *                          |
         *                          |
         *
         * So we have two conditions:
         *
         *   (a)  AT  || TB          (collinearity condition)
         *   (b)  PT _|_ AB          (orthogonality condition)
         *
         *      a2-t2       t2-b2
         *     -------  =  -------           (1)
         *      a1-t1       t1-b1
         *
         *      p2-t2         a1-b1
         *     -------  =  - -------         (2)
         *      p1-t1         a2-b2
         *
         * Multiplying (1) and (2) with denominators and simplifying gives
         *
         *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                  (1')
         *
         *    p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0    (2')
         *
         */

        var a1 = l.point1.symbolic.x;
        var a2 = l.point1.symbolic.y;
        var b1 = l.point2.symbolic.x;
        var b2 = l.point2.symbolic.y;
        var p1 = p.symbolic.x;
        var p2 = p.symbolic.y;
        var t1 = t.symbolic.x;
        var t2 = t.symbolic.y;

        var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
        var poly2 = '('+p2+')*('+a2+')-('+p2+')*('+b2+')-('+t2+')*('+a2+')+('+t2+')*('+b2+')+('+p1+')*('+a1+')-('+p1+')*('+b1+')-('+t1+')*('+a1+')+('+t1+')*('+b1+')';

        return [poly1, poly2];
    };

    return t;
};


/**
 * @class This element is used to provide a constructor for a perpendicular segment.
 * @pseudo
 * @description  A perpendicular is a composition of two elements: a line segment and a point. The line segment is orthogonal
 * to a given line and contains a given point and meets the given line in the perpendicular point.
 * @name Perpendicular
 * @constructor
 * @type JXG.Line
 * @augments Segment
 * @return An array containing two elements: A {@link JXG.Line} object in the first component and a
 * {@link JXG.Point} element in the second component. The line segment is orthogonal to the given line and meets it
 * in the returned point.
 * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and
 * will contain p. The perpendicular point is the intersection point of the two lines.
 * @example
 * // Create a perpendicular
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var l1 = board.create('line', [p1, p2]);
 *
 * var p3 = board.create('point', [3.0, 3.0]);
 * var perp1 = board.create('perpendicularsegment', [l1, p3]);
 * </pre><div id="037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var pex1_board = JXG.JSXGraph.initBoard('037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);
 *   var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);
 *   var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);
 *   var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);
 *   var pex1_perp1 = pex1_board.create('perpendicularsegment', [pex1_l1, pex1_p3]);
 * </script><pre>
 */
JXG.createPerpendicularSegment = function(board, parents, attributes) {
    var p, l, pd, t, attr;

    parents[0] = JXG.getReference(board, parents[0]);
    parents[1] = JXG.getReference(board, parents[1]);

    if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
        l = parents[1];
        p = parents[0];
    }
    else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
        l = parents[0];
        p = parents[1];
    } else {
        throw new Error("JSXGraph: Can't create perpendicular with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [line,point]");
    }
    attr = JXG.copyAttributes(attributes, board.options, 'perpendicularsegment', 'point');
    t = JXG.createPerpendicularPoint(board, [l, p], attr);

    t.dump = false;

    if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
    attr = JXG.copyAttributes(attributes, board.options, 'perpendicularsegment');
    pd = JXG.createLine(board, [function () { return (JXG.Math.Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]); }], attr);

    /**
     * Helper point
     * @memberOf PerpendicularSegment.prototype
     * @type PerpendicularPoint
     * @name point
     */
    pd.point = t;

    pd.elType = 'perpendicularsegment';
    pd.parents = [p.id, l.id];
    pd.subs = {
        point: t
    };

    return pd;
};

/**
 * @class The midpoint element constructs a point in the middle of two given points.
 * @pseudo
 * @description A midpoint is given by two points. It is collinear to the given points and the distance
 * is the same to each of the given points, i.e. it is in the middle of the given points.
 * @constructor
 * @name Midpoint
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2.
 * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of
 * the given line l.
 * @example
 * // Create base elements: 2 points and 1 line
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
 *
 * var mp1 = board.create('midpoint', [p1, p2]);
 * var mp2 = board.create('midpoint', [l1]);
 * </pre><div id="7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var mpex1_board = JXG.JSXGraph.initBoard('7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]);
 *   var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]);
 *   var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
 *   var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]);
 *   var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]);
 * </script><pre>
 */
JXG.createMidpoint = function(board, parents, attributes) {
    var a, b, t;

    if(parents.length == 2 && JXG.isPoint(parents[0]) && JXG.isPoint(parents[1])) {
        a = parents[0];
        b = parents[1];
    }
    else if(parents.length == 1 && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
        a = parents[0].point1;
        b = parents[0].point2;
    }
    else {
        throw new Error("JSXGraph: Can't create midpoint." +
                        "\nPossible parent types: [point,point], [line]");
    }

    t = board.create('point', [
                               function () {
                                var x = a.coords.usrCoords[1] + b.coords.usrCoords[1];
                                if (isNaN(x) || Math.abs(a.coords.usrCoords[0])<JXG.Math.eps || Math.abs(b.coords.usrCoords[0])<JXG.Math.eps) {
                                    return NaN;
                                } else {
                                    return x*0.5;
                                }
                               },
                               function () {
                                var y = a.coords.usrCoords[2] + b.coords.usrCoords[2];
                                if (isNaN(y) || Math.abs(a.coords.usrCoords[0])<JXG.Math.eps || Math.abs(b.coords.usrCoords[0])<JXG.Math.eps) {
                                    return NaN;
                                } else {
                                    return y*0.5;
                                }
                              }], attributes);
    a.addChild(t);
    b.addChild(t);

    t.elType = 'midpoint';
    t.parents = [a.id, b.id];

    t.prepareUpdate().update();

    t.generatePolynomial = function() {
        /*
         *  Midpoint takes two point A and B or line L (with points P and Q) and creates point T:
         *
         *  L (not necessarily)
         *  ----------x------------------x------------------x--------
         *            A (a1,a2)          T (t1,t2)          B (b1,b2)
         *
         * So we have two conditions:
         *
         *   (a)   AT  ||  TB           (collinearity condition)
         *   (b)  [AT] == [TB]          (equidistant condition)
         *
         *      a2-t2       t2-b2
         *     -------  =  -------                                         (1)
         *      a1-t1       t1-b1
         *
         *     (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2       (2)
         *
         *
         * Multiplying (1) with denominators and simplifying (1) and (2) gives
         *
         *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                      (1')
         *
         *    a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0    (2')
         *
         */

        var a1 = a.symbolic.x;
        var a2 = a.symbolic.y;
        var b1 = b.symbolic.x;
        var b2 = b.symbolic.y;
        var t1 = t.symbolic.x;
        var t2 = t.symbolic.y;

        var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
        var poly2 = '('+a1+')^2 - 2*('+a1+')*('+t1+')+('+a2+')^2-2*('+a2+')*('+t2+')-('+b1+')^2+2*('+b1+')*('+t1+')-('+b2+')^2+2*('+b2+')*('+t2+')';

        return [poly1, poly2];
    };

    return t;
};

/**
 * @class This element is used to construct a parallel point.
 * @pseudo
 * @description A parallel point is given by three points. Taking the euclidean vector from the first to the
 * second point, the parallel point is determined by adding that vector to the third point.
 * The line determined by the first two points is parallel to the line determined by the third point and the constructed point.
 * @constructor
 * @name Parallelpoint
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 Taking the euclidean vector <tt>v=p2-p1</tt> the parallel point is determined by
 * <tt>p4 = p3+v</tt>
 * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l.
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var pp1 = board.create('parallelpoint', [p1, p2, p3]);
 * </pre><div id="488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var ppex1_board = JXG.JSXGraph.initBoard('488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]);
 *   var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]);
 *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
 *   var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]);
 * </script><pre>
 */
JXG.createParallelPoint = function(board, parents, attributes) {
    var a, b, c, p;

    if(parents.length == 3 && parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) {
        a = parents[0];
        b = parents[1];
        c = parents[2];
    } else if (parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
        c = parents[0];
        a = parents[1].point1;
        b = parents[1].point2;
    } else if (parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
        c = parents[1];
        a = parents[0].point1;
        b = parents[0].point2;
    }
    else {
        throw new Error("JSXGraph: Can't create parallel point with parent types '" +
                        (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
                        "\nPossible parent types: [line,point], [point,point,point]");
    }

    p = board.create('point', [function () { return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1]; },
                               function () { return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2]; }],
                               attributes);
	// required for algorithms requiring dependencies between elements
	a.addChild(p);
	b.addChild(p);
    c.addChild(p);

    p.elType = 'parallelpoint';
    p.parents = [a.id, b.id, c.id];

    // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update.
    // can be removed if the above issue is resolved.
    p.prepareUpdate().update();

    p.generatePolynomial = function() {
        /*
         *  Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T:
         *
         *
         *                     C (c1,c2)                             T (t1,t2)
         *                      x                                     x
         *                     /                                     /
         *                    /                                     /
         *                   /                                     /
         *                  /                                     /
         *                 /                                     /
         *                /                                     /
         *               /                                     /
         *              /                                     /
         *  L (opt)    /                                     /
         *  ----------x-------------------------------------x--------
         *            A (a1,a2)                             B (b1,b2)
         *
         * So we have two conditions:
         *
         *   (a)   CT  ||  AB           (collinearity condition I)
         *   (b)   BT  ||  AC           (collinearity condition II)
         *
         * The corresponding equations are
         *
         *    (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0         (1)
         *    (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0         (2)
         *
         * Simplifying (1) and (2) gives
         *
         *    b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0      (1')
         *    t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0      (2')
         *
         */

        var a1 = a.symbolic.x;
        var a2 = a.symbolic.y;
        var b1 = b.symbolic.x;
        var b2 = b.symbolic.y;
        var c1 = c.symbolic.x;
        var c2 = c.symbolic.y;
        var t1 = p.symbolic.x;
        var t2 = p.symbolic.y;

        var poly1 =  '('+b2+')*('+t1+')-('+b2+')*('+c1+')-('+a2+')*('+t1+')+('+a2+')*('+c1+')-('+t2+')*('+b1+')+('+t2+')*('+a1+')+('+c2+')*('+b1+')-('+c2+')*('+a1+')';
        var poly2 =  '('+t2+')*('+a1+')-('+t2+')*('+c1+')-('+b2+')*('+a1+')+('+b2+')*('+c1+')-('+t1+')*('+a2+')+('+t1+')*('+c2+')+('+b1+')*('+a2+')-('+b1+')*('+c2+')';

        return [poly1, poly2];
    };

    return p;
};


/**
 * @class A parallel is a line through a given point with the same slope as a given line.
 * @pseudo
 * @name Parallel
 * @augments Line
 * @constructor
 * @type JXG.Line
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l.
 * @example
 * // Create a parallel
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var l1 = board.create('line', [p1, p2]);
 *
 * var p3 = board.create('point', [3.0, 3.0]);
 * var pl1 = board.create('parallel', [l1, p3]);
 * </pre><div id="24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var plex1_board = JXG.JSXGraph.initBoard('24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
 *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
 *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
 *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
 *   var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);
 * </script><pre>
 */
JXG.createParallel = function(board, parents, attributes) {
    var p, pp, pl, li, attr;

    /* parallel point polynomials are done in createParallelPoint */
    /*
    try {
        attr = JXG.copyAttributes(attributes, board.options, 'parallel', 'point');
        pp = JXG.createParallelPoint(board, parents, attr);     // non-visible point
    } catch (e) {
        throw new Error("JSXGraph: Can't create parallel with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [line,point], [point,point,point]");
    }
    */

    p = null;
    if(parents.length == 3) {
        // line through point parents[2] which is parallel to line through parents[0] and parents[1]
        p = parents[2];
        li = function() { return JXG.Math.crossProduct(parents[0].coords.usrCoords, parents[1].coords.usrCoords); };

        //pp = [parents[0].id, parents[1].id, p.id];
    } else if (parents[0].elementClass == JXG.OBJECT_CLASS_POINT) {
        // Parallel to line parents[1] through point parents[0]
        p = parents[0];
        li = function() { return parents[1].stdform; };
        //pp = [parents[1].id, p.id];
    } else if (parents[1].elementClass == JXG.OBJECT_CLASS_POINT) {
        // Parallel to line parents[0] through point parents[1]
        p = parents[1];
        li = function() { return parents[0].stdform; };
        //pp = [parents[0].id, p.id];
    }

    if (!JXG.exists(attributes.layer)) {
        attributes.layer = board.options.layer.line;
    }

    attr = JXG.copyAttributes(attributes, board.options, 'parallel', 'point');
	pp = board.create('point', [function() {
            return JXG.Math.crossProduct([1,0,0], li());
        }], attr);

    pp.isDraggable = true;

    attr = JXG.copyAttributes(attributes, board.options, 'parallel');
    pl = board.create('line', [p, pp], attr);
    /*
    pl = board.create('line', [function() {
            var l = li();
            return [ -(p.X()*l[1]+p.Y()*l[2]), p.Z()*l[1], p.Z()*l[2]];
        }], attr);
    */

    pl.elType = 'parallel';
    pl.parents = [parents[0].id, parents[1].id];
    if (parents.length === 3) {
        pl.parents.push(parents[2].id);
    }

    /**
     * Helper point used to create the parallel line. This point lies on the line at infinity, hence it's not visible,
     * not even with visible set to <tt>true</tt>. Creating another line through this point would make that other line
     * parallel to the create parallel.
     * @memberOf Parallel.prototype
     * @name point
     * @type JXG.Point
     */
    pl.point = pp;

    return pl;
};

/**
 * @class An arrow parallel is a parallel segment with an arrow attached.
 * @pseudo
 * @constructor
 * @name Arrowparallel
 * @type Parallel
 * @augments Parallel
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line_JXG.Point} l,p The constructed arrow contains p and has the same slope as l.
 * @example
 * // Create a parallel
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var l1 = board.create('line', [p1, p2]);
 *
 * var p3 = board.create('point', [3.0, 3.0]);
 * var pl1 = board.create('arrowparallel', [l1, p3]);
 * </pre><div id="eeacdf99-036f-4e83-aeb6-f7388423e369" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var plex1_board = JXG.JSXGraph.initBoard('eeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
 *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
 *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
 *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
 *   var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_l1, plex1_p3]);
 * })();
 * </script><pre>
 */
JXG.createArrowParallel = function(board, parents, attributes) {
    var p;

    /* parallel arrow point polynomials are done in createParallelPoint */
    try {
        attributes['firstArrow'] = false;
        attributes['lastArrow'] = true;
        p = JXG.createParallel(board, parents, attributes).setStraight(false, false); //.setArrow(false,true);
        p.elType = 'arrowparallel';

        // parents are set in createParallel

        return p;
    } catch (e) {
        throw new Error("JSXGraph: Can't create arrowparallel with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [line,point], [point,point,point]");
    }
};

/**
 * @class Constructs a normal.
 * @pseudo
 * @description A normal is a line through a given point on a element of type line, circle, curve, or turtle and orthogonal to that object.
 * @constructor
 * @name Normal
 * @type JXG.Line
 * @augments JXG.Line
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line,JXG.Circle,JXG.Curve,JXG.Turtle_JXG.Point} o,p The constructed line contains p which lies on the object and is orthogonal
 * to the tangent to the object in the given point.
 * @param {Glider} p Works like above, however the object is given by {@link Glider#slideObject}.
 * @example
 * // Create a normal to a circle.
 * var p1 = board.create('point', [2.0, 2.0]);
 * var p2 = board.create('point', [3.0, 2.0]);
 * var c1 = board.create('circle', [p1, p2]);
 *
 * var norm1 = board.create('normal', [c1, p2]);
 * </pre><div id="4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var nlex1_board = JXG.JSXGraph.initBoard('4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]);
 *   var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]);
 *   var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]);
 *
 *   // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]);
 *   var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]);
 * </script><pre>
 */
JXG.createNormal = function(board, parents, attributes) {
    /* TODO normal polynomials */
    var p, c, l, i, attr, pp, attrp;

    if (parents.length==1) { // One arguments: glider on line, circle or curve
        p = parents[0];
        c = p.slideObject;
    } else if (parents.length==2) { // Two arguments: (point,line), (point,circle), (line,point) or (circle,point)
        if (JXG.isPoint(parents[0])) {
            p = parents[0];
            c = parents[1];
        } else if (JXG.isPoint(parents[1])) {
            c = parents[0];
            p = parents[1];
        } else {
            throw new Error("JSXGraph: Can't create normal with parent types '" +
                            (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                            "\nPossible parent types: [point,line], [point,circle], [glider]");
        }
    } else {
        throw new Error("JSXGraph: Can't create normal with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,line], [point,circle], [glider]");
    }

    attr = JXG.copyAttributes(attributes, board.options, 'normal');
    if(c.elementClass==JXG.OBJECT_CLASS_LINE) {
        // Homogeneous version:
        // orthogonal(l,p) = (F^\delta\cdot l)\times p
        /*
        l = board.create('line', [
                    function(){ return c.stdform[1]*p.Y()-c.stdform[2]*p.X();},
                    function(){ return c.stdform[2]*p.Z();},
                    function(){ return -c.stdform[1]*p.Z();}
                    ], attributes );
        */
        // Private point
        attrp = JXG.copyAttributes(attributes, board.options, 'normal', 'point');
        pp = board.create('point', [function() {
                var p = JXG.Math.crossProduct([1,0,0], c.stdform);
                return [p[0], -p[2], p[1]];
            }], attrp);
        pp.isDraggable = true;

        l = board.create('line', [p, pp], attr);

        /**
         * A helper point used to create a normal to a {@link JXG.Line} object. For normals to circles or curves this
         * element is <tt>undefined</tt>.
         * @type JXG.Point
         * @name point
         * @memberOf Normal.prototype
         */
        l.point = pp;
    } else if(c.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
        l = board.create('line', [c.midpoint,p], attr);
    } else if (c.elementClass == JXG.OBJECT_CLASS_CURVE) {
        if (c.visProp.curvetype!='plot') {
            var g = c.X;
            var f = c.Y;
            l = board.create('line', [
                    function(){ return -p.X()*board.D(g)(p.position)-p.Y()*board.D(f)(p.position);},
                    function(){ return board.D(g)(p.position);},
                    function(){ return board.D(f)(p.position);}
                    ], attr);
        } else {                         // curveType 'plot'
            l = board.create('line', [
                    function(){ var i=Math.floor(p.position);
                                var lbda = p.position-i;
                                if (i==c.numberPoints-1) {i--; lbda=1; }
                                if (i<0) return 1.0;
                                return (c.Y(i)+lbda*(c.Y(i+1)-c.Y(i)))*(c.Y(i)-c.Y(i+1))-(c.X(i)+lbda*(c.X(i+1)-c.X(i)))*(c.X(i+1)-c.X(i));},
                    function(){ var i=Math.floor(p.position);
                                if (i==c.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return c.X(i+1)-c.X(i);},
                    function(){ var i=Math.floor(p.position);
                                if (i==c.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return c.Y(i+1)-c.Y(i);}
                    ], attr );
        }
    } else if (c.type == JXG.OBJECT_TYPE_TURTLE) {
            l = board.create('line', [
                    function(){ var i=Math.floor(p.position);
                                var lbda = p.position-i;
                                var el,j;
                                for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
                                    el = c.objects[j];
                                    if (el.type==JXG.OBJECT_TYPE_CURVE) {
                                        if (i<el.numberPoints) break;
                                        i-=el.numberPoints;
                                    }
                                }
                                if (i==el.numberPoints-1) { i--; lbda=1.0; }
                                if (i<0) return 1.0;
                                return (el.Y(i)+lbda*(el.Y(i+1)-el.Y(i)))*(el.Y(i)-el.Y(i+1))-(el.X(i)+lbda*(el.X(i+1)-el.X(i)))*(el.X(i+1)-el.X(i));},
                    function(){ var i=Math.floor(p.position);
                                var el,j;
                                for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
                                    el = c.objects[j];
                                    if (el.type==JXG.OBJECT_TYPE_CURVE) {
                                        if (i<el.numberPoints) break;
                                        i-=el.numberPoints;
                                    }
                                }
                                if (i==el.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return el.X(i+1)-el.X(i);},
                    function(){ var i=Math.floor(p.position);
                                var el,j;
                                for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
                                    el = c.objects[j];
                                    if (el.type==JXG.OBJECT_TYPE_CURVE) {
                                        if (i<el.numberPoints) break;
                                        i-=el.numberPoints;
                                    }
                                }
                                if (i==el.numberPoints-1) i--;
                                if (i<0) return 0.0;
                                return el.Y(i+1)-el.Y(i);}
                    ], attr );
    }
    else {
        throw new Error("JSXGraph: Can't create normal with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,line], [point,circle], [glider]");
    }

    l.parents = [];
    for (i = 0; i < parents.length; i++) {
        l.parents.push(parents[i].id);
    }
    l.elType = 'normal';

    return l;
};

/**
 * @class A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and
 * C and divides the angle ABC into two equal sized parts.
 * @pseudo
 * @constructor
 * @name Bisector
 * @type JXG.Line
 * @augments JXG.Line
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will
 * be divided into two equal angles.
 * @example
 * var p1 = board.create('point', [6.0, 4.0]);
 * var p2 = board.create('point', [3.0, 2.0]);
 * var p3 = board.create('point', [1.0, 7.0]);
 *
 * var bi1 = board.create('bisector', [p1, p2, p3]);
 * </pre><div id="0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var p1 = board.create('point', [6.0, 4.0]);
 *   var p2 = board.create('point', [3.0, 2.0]);
 *   var p3 = board.create('point', [1.0, 7.0]);
 *   var bi1 = board.create('bisector', [p1, p2, p3]);
 * })();
 * </script><pre>
 */
JXG.createBisector = function(board, parents, attributes) {
    var p, l, i, attr;

    /* TODO bisector polynomials */
    if(parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) {
        // hidden and fixed helper
        attr = JXG.copyAttributes(attributes, board.options, 'bisector', 'point');
        p = board.create('point', [function () { return JXG.Math.Geometry.angleBisector(parents[0], parents[1], parents[2], board); }], attr);
        p.dump = false;

        for(i=0; i<3; i++)
            parents[i].addChild(p); // required for algorithm requiring dependencies between elements

        if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
        attr = JXG.copyAttributes(attributes, board.options, 'bisector');
        l = JXG.createLine(board, [parents[1], p], attr);

        /**
         * Helper point
         * @memberOf Bisector.prototype
         * @type Point
         * @name point
         */
        l.point = p;

        l.elType = 'bisector';
        l.parents = [parents[0].id, parents[1].id, parents[2].id];
        l.subs = {
            point: p
        };

        return l;
    }
    else {
        throw new Error("JSXGraph: Can't create angle bisector with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,point,point]");
    }
};

/**
 * @class Bisector lines are similar to {@link Bisector} but takes two lines as parent elements. The resulting element is
 * a composition of two lines.
 * @pseudo
 * @constructor
 * @name Bisectorlines
 * @type JXG.Composition
 * @augments JXG.Composition
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each
 * be divided into two equal angles.
 * @example
 * var p1 = board.create('point', [6.0, 4.0]);
 * var p2 = board.create('point', [3.0, 2.0]);
 * var p3 = board.create('point', [1.0, 7.0]);
 * var p4 = board.create('point', [3.0, 0.0]);
 * var l1 = board.create('line', [p1, p2]);
 * var l2 = board.create('line', [p3, p4]);
 *
 * var bi1 = board.create('bisectorlines', [l1, l2]);
 * </pre><div id="3121ff67-44f0-4dda-bb10-9cda0b80bf18" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var p1 = board.create('point', [6.0, 4.0]);
 *   var p2 = board.create('point', [3.0, 2.0]);
 *   var p3 = board.create('point', [1.0, 7.0]);
 *   var p4 = board.create('point', [3.0, 0.0]);
 *   var l1 = board.create('line', [p1, p2]);
 *   var l2 = board.create('line', [p3, p4]);
 *   var bi1 = board.create('bisectorlines', [l1, l2]);
 * })();
 * </script><pre>
 */
JXG.createAngularBisectorsOfTwoLines = function(board, parents, attributes) {
    //
    // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation:
    // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2)

    var l1 = JXG.getReference(board,parents[0]),
        l2 = JXG.getReference(board,parents[1]),
        g1, g2, attr,
        ret;

    if(l1.elementClass != JXG.OBJECT_CLASS_LINE || l2.elementClass != JXG.OBJECT_CLASS_LINE) {
        throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [line,line]");
    }

    if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
    attr = JXG.copyAttributes(attributes, board.options, 'bisectorlines', 'line1');
    g1 = board.create('line',[
        function(){
            var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
            var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
            return l1.stdform[0]/d1-l2.stdform[0]/d2;
        },
        function(){
            var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
            var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
            return l1.stdform[1]/d1-l2.stdform[1]/d2;
        },
        function(){
            var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
            var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
            return l1.stdform[2]/d1-l2.stdform[2]/d2;
        }
    ], attr);

    if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
    attr = JXG.copyAttributes(attributes, board.options, 'bisectorlines', 'line2');
    g2 = board.create('line',[
        function(){
            var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
            var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
            return l1.stdform[0]/d1+l2.stdform[0]/d2;
        },
        function(){
            var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
            var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
            return l1.stdform[1]/d1+l2.stdform[1]/d2;
        },
        function(){
            var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
            var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
            return l1.stdform[2]/d1+l2.stdform[2]/d2;
        }
    ], attr);

    // documentation
    /**
     * First line.
     * @memberOf Bisectorlines.prototype
     * @name line1
     * @type Line
     */

    /**
     * Second line.
     * @memberOf Bisectorlines.prototype
     * @name line2
     * @type Line
     */

    ret = new JXG.Composition({line1: g1, line2: g2});

    g1.dump = false;
    g2.dump = false;

    ret.elType = 'bisectorlines';
    ret.parents = [l1.id, l2.id];
    ret.subs = {
        line1: g1,
        line2: g2
    };

    return ret;
};

/**
 * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter
 * is constructed by providing three points.
 * @pseudo
 * @description A circumcenter is given by three points which are all lying on the circle with the
 * constructed circumcenter as the midpoint.
 * @constructor
 * @name Circumcenter
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined
 * by p1, p2, and p3.
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var cc1 = board.create('circumcenter', [p1, p2, p3]);
 * </pre><div id="e8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var ccmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]);
 *   var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]);
 *   var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]);
 *   var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]);
 * </script><pre>
 */
JXG.createCircumcircleMidpoint = function(board, parents, attributes) {
    var p, i;

    if( parents[0].elementClass == JXG.OBJECT_CLASS_POINT
       && parents[1].elementClass == JXG.OBJECT_CLASS_POINT
       && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) {
        p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.circumcenterMidpoint(parents[0], parents[1], parents[2], board); }], attributes);

        for (i = 0; i < 3; i++) {
            parents[i].addChild(p);
        }

        p.elType = 'circumcenter';
        p.parents = [parents[0].id, parents[1].id, parents[2].id];

        p.generatePolynomial = function() {
                /*
                 *  CircumcircleMidpoint takes three points A, B and C  and creates point M, which is the circumcenter of A, B, and C.
                 *
                 *
                 * So we have two conditions:
                 *
                 *   (a)   CT  ==  AT           (distance condition I)
                 *   (b)   BT  ==  AT           (distance condition II)
                 *
                 */

            var a1 = a.symbolic.x;
            var a2 = a.symbolic.y;
            var b1 = b.symbolic.x;
            var b2 = b.symbolic.y;
            var c1 = c.symbolic.x;
            var c2 = c.symbolic.y;
            var t1 = p.symbolic.x;
            var t2 = p.symbolic.y;

            var poly1 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',b1,'))^2-((',t2,')-(',b2,'))^2'].join('');
            var poly2 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',c1,'))^2-((',t2,')-(',c2,'))^2'].join('');

            return [poly1, poly2];
        };

        return p;
    }
    else {
        throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" +
                        (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
                        "\nPossible parent types: [point,point,point]");
    }
};

/**
 * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html}
 * @pseudo
 * @constructor
 * @name Incenter
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described
 * by p1, p2, and p3.
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var ic1 = board.create('incenter', [p1, p2, p3]);
 * </pre><div id="e8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var icmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]);
 *   var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]);
 *   var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]);
 *   var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]);
 * </script><pre>
 */
JXG.createIncenter = function(board, parents, attributes) {
    var p, c,
        A, B, C;

    if(parents.length >= 3 && JXG.isPoint(parents[0]) && JXG.isPoint(parents[1]) && JXG.isPoint(parents[2])) {
        A = parents[0];
        B = parents[1];
        C = parents[2];

        p = board.create('point', [function() {
            var a, b, c;

            a = Math.sqrt((B.X() - C.X())*(B.X() - C.X()) + (B.Y() - C.Y())*(B.Y() - C.Y()));
            b = Math.sqrt((A.X() - C.X())*(A.X() - C.X()) + (A.Y() - C.Y())*(A.Y() - C.Y()));
            c = Math.sqrt((B.X() - A.X())*(B.X() - A.X()) + (B.Y() - A.Y())*(B.Y() - A.Y()));

            return new JXG.Coords(JXG.COORDS_BY_USER, [(a*A.X()+b*B.X()+c*C.X())/(a+b+c), (a*A.Y()+b*B.Y()+c*C.Y())/(a+b+c)], board);
        }], attributes);

        p.elType = 'incenter';
        p.parents = [parents[0].id, parents[1].id, parents[2].id];

    } else {
        throw new Error("JSXGraph: Can't create incenter with parent types '" +
            (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
            "\nPossible parent types: [point,point,point]");
    }

    return p;
};

/**
 * @class A circumcircle is given by three points which are all lying on the circle.
 * @pseudo
 * @constructor
 * @name Circumcircle
 * @type JXG.Circle
 * @augments JXG.Circle
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed element is the circle determined by <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var cc1 = board.create('circumcircle', [p1, p2, p3]);
 * </pre><div id="e65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var ccex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]);
 *   var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]);
 *   var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]);
 *   var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]);
 * </script><pre>
 */
JXG.createCircumcircle = function(board, parents, attributes) {
    var p, c, attr;

    try {
        attr = JXG.copyAttributes(attributes, board.options, 'circumcircle', 'center');
        p = JXG.createCircumcircleMidpoint(board, parents, attr);

        p.dump = false;

        if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.circle;
        attr = JXG.copyAttributes(attributes, board.options, 'circumcircle');
        c = JXG.createCircle(board, [p, parents[0]], attr);

        c.elType = 'circumcircle';
        c.parents = [parents[0].id, parents[1].id, parents[2].id];
        c.subs = {
            center: p
        };
    } catch(e) {
        throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
                        (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
                        "\nPossible parent types: [point,point,point]");
    }

    // p is already stored as midpoint in c so there's no need to store it explicitly.

    return c;
};

/**
 * @class An incircle is given by three points.
 * @pseudo
 * @constructor
 * @name Incircle
 * @type JXG.Circle
 * @augments JXG.Circle
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of
 * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.
 * @example
 * var p1 = board.create('point', [0.0, 2.0]);
 * var p2 = board.create('point', [2.0, 1.0]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var ic1 = board.create('incircle', [p1, p2, p3]);
 * </pre><div id="e65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var icex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var icex1_p1 = icex1_board.create('point', [0.0, 2.0]);
 *   var icex1_p2 = icex1_board.create('point', [6.0, 1.0]);
 *   var icex1_p3 = icex1_board.create('point', [3.0, 7.0]);
 *   var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]);
 * </script><pre>
 */
JXG.createIncircle = function(board, parents, attributes) {
    var p, c, attr, ret;

    try {
        attr = JXG.copyAttributes(attributes, board.options, 'incircle', 'center');
        p = JXG.createIncenter(board, parents, attr);

        p.dump = false;

        if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.circle;
        attr = JXG.copyAttributes(attributes, board.options, 'incircle');
        c = JXG.createCircle(board, [p, function() {
            var a = Math.sqrt((parents[1].X() - parents[2].X())*(parents[1].X() - parents[2].X()) + (parents[1].Y() - parents[2].Y())*(parents[1].Y() - parents[2].Y())),
                b = Math.sqrt((parents[0].X() - parents[2].X())*(parents[0].X() - parents[2].X()) + (parents[0].Y() - parents[2].Y())*(parents[0].Y() - parents[2].Y())),
                c = Math.sqrt((parents[1].X() - parents[0].X())*(parents[1].X() - parents[0].X()) + (parents[1].Y() - parents[0].Y())*(parents[1].Y() - parents[0].Y())),
                s = (a+b+c)/2;

            return Math.sqrt(((s-a)*(s-b)*(s-c))/s);
        }], attr);

        c.elType = 'incircle';
        c.parents = [parents[0].id, parents[1].id, parents[2].id];

        /**
         * The center of the incircle
         * @memberOf Incircle.prototype
         * @type Incenter
         * @name center
         */
        c.center = p;

        c.subs = {
            center: p
        };
    } catch(e) {
        throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
                        (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
                        "\nPossible parent types: [point,point,point]");
    }

    // p is already stored as midpoint in c so there's no need to store it explicitly.

    return c;
};

/**
 * @class This element is used to construct a reflected point.
 * @pseudo
 * @description A reflected point is given by a point and a line. It is determined by the reflection of the given point
 * against the given line.
 * @constructor
 * @name Reflection
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Line} p,l The reflection point is the reflection of p against l.
 * @example
 * var p1 = board.create('point', [0.0, 4.0]);
 * var p2 = board.create('point', [6.0, 1.0]);
 * var l1 = board.create('line', [p1, p2]);
 * var p3 = board.create('point', [3.0, 3.0]);
 *
 * var rp1 = board.create('reflection', [p3, l1]);
 * </pre><div id="087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var rpex1_board = JXG.JSXGraph.initBoard('087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]);
 *   var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]);
 *   var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]);
 *   var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]);
 *   var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]);
 * </script><pre>
 */
JXG.createReflection = function(board, parents, attributes) {
    var l, p, r, t;

    if(parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
        p = parents[0];
        l = parents[1];
    }
    else if(parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
        p = parents[1];
        l = parents[0];
    }
    else {
        throw new Error("JSXGraph: Can't create reflection point with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [line,point]");
    }

    //r = JXG.createPoint(board, [function () { return JXG.Math.Geometry.reflection(l, p, board); }], attributes);
    t = JXG.createTransform(board, [l], {type:'reflect'});
    r = JXG.createPoint(board, [p, t], attributes);
    p.addChild(r);
    l.addChild(r);

    r.elType = 'reflection';
    r.parents = [parents[0].id, parents[1].id];

    r.prepareUpdate().update();

    r.generatePolynomial = function() {
        /*
         *  Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.
         *  L is defined by two points A and B.
         *
         * So we have two conditions:
         *
         *   (a)   RP  _|_  AB            (orthogonality condition)
         *   (b)   AR  ==   AP            (distance condition)
         *
         */

        var a1 = l.point1.symbolic.x;
        var a2 = l.point1.symbolic.y;
        var b1 = l.point2.symbolic.x;
        var b2 = l.point2.symbolic.y;
        var p1 = p.symbolic.x;
        var p2 = p.symbolic.y;
        var r1 = r.symbolic.x;
        var r2 = r.symbolic.y;

        var poly1 = ['((',r2,')-(',p2,'))*((',a2,')-(',b2,'))+((',a1,')-(',b1,'))*((',r1,')-(',p1,'))'].join('');
        var poly2 = ['((',r1,')-(',a1,'))^2+((',r2,')-(',a2,'))^2-((',p1,')-(',a1,'))^2-((',p2,')-(',a2,'))^2'].join('');

        return [poly1, poly2];
    };

    return r;
};

/**
 * @class A mirror point will be constructed.
 * @pseudo
 * @description A mirror point is determined by the reflection of a given point against another given point.
 * @constructor
 * @name Mirrorpoint
 * @type JXG.Point
 * @augments JXG.Point
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.
 * @example
 * var p1 = board.create('point', [3.0, 3.0]);
 * var p2 = board.create('point', [6.0, 1.0]);
 *
 * var mp1 = board.create('mirrorpoint', [p1, p2]);
 * </pre><div id="7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var mpex1_board = JXG.JSXGraph.initBoard('7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 *   var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);
 *   var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);
 *   var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);
 * </script><pre>
 */
JXG.createMirrorPoint = function(board, parents, attributes) {
    var p, i;

    /* TODO mirror polynomials */
    if(JXG.isPoint(parents[0]) && JXG.isPoint(parents[1])) {
        p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.rotation(parents[0], parents[1], Math.PI, board); }], attributes);

        for(i = 0; i < 2; i++) {
            parents[i].addChild(p);
        }

        p.elType = 'mirrorpoint';
        p.parents = [parents[0].id, parents[1].id];
    }
    else {
        throw new Error("JSXGraph: Can't create mirror point with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [point,point]");
    }

    p.prepareUpdate().update();

    return p;
};

/**
 * @class This element is used to visualize the integral of a given curve over a given interval.
 * @pseudo
 * @description The Integral element is used to visualize the area under a given curve over a given interval
 * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,
 * the gliders are used to change the interval dynamically.
 * @constructor
 * @name Integral
 * @type JXG.Curve
 * @augments JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis
 * within the interval <tt>i</tt>.
 * @example
 * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);
 * var i1 = board.create('integral', [[-1.0, 4.0], c1]);
 * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var intex1_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});
 *   var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]);
 *   var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);
 * </script><pre>
 */
JXG.createIntegral = function(board, parents, attributes) {
    var interval, curve, attr,
        start = 0, end = 0, startx, starty, endx, endy, factor = 1,
        pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,
        Int, t, p;

    if(JXG.isArray(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_CURVE) {
        interval = parents[0];
        curve = parents[1];
    } else if(JXG.isArray(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_CURVE) {
        interval = parents[1];
        curve = parents[0];
    } else {
        throw new Error("JSXGraph: Can't create integral with parent types '" +
                        (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
                        "\nPossible parent types: [[number|function,number|function],curve]");
    }

    // Correct the interval if necessary - NOT ANYMORE, GGB's fault
    start = interval[0];
    end = interval[1];

    if(JXG.isFunction(start)) {
        startx = start;
        starty = function () { return curve.Y(startx()); };
        start = startx();
    } else {
        startx = start;
        starty = curve.Y(start);
    }

    if(JXG.isFunction(start)) {
        endx = end;
        endy = function () { return curve.Y(endx()); };
        end = endx();
    } else {
        endx = end;
        endy = curve.Y(end);
    }

    if(end < start) {
        factor = -1;
    }

    attr = JXG.copyAttributes(attributes, board.options, 'integral', 'curveLeft');
    pa_on_curve = board.create('glider', [startx, starty, curve], attr);
    if(JXG.isFunction(startx))
        pa_on_curve.hideElement();

    attr = JXG.copyAttributes(attributes, board.options, 'integral', 'baseLeft');
    pa_on_axis = board.create('point', [function () { return pa_on_curve.X(); }, 0], attr);

    //pa_on_curve.addChild(pa_on_axis);

    attr = JXG.copyAttributes(attributes, board.options, 'integral', 'curveRight');
    pb_on_curve = board.create('glider', [endx, endy, curve], attr);
    if(JXG.isFunction(endx))
        pb_on_curve.hideElement();

    attr = JXG.copyAttributes(attributes, board.options, 'integral', 'baseRight');
    pb_on_axis = board.create('point', [function () { return pb_on_curve.X(); }, 0], attr);

    //pb_on_curve.addChild(pb_on_axis);

    attr = JXG.copyAttributes(attributes, board.options, 'integral');
    if(attr.withLabel !== false) {
        attr = JXG.copyAttributes(attributes, board.options, 'integral', 'label');
        t = board.create('text', [
            function () { return pb_on_curve.X() + 0.2; },
            function () { return pb_on_curve.Y() - 0.8; },
            function () {
                    var Int = JXG.Math.Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
                    return '&int; = ' + (Int).toFixed(4);
                }
            ], attr);

        t.dump = false;

        pa_on_curve.addChild(t);
        pb_on_curve.addChild(t);
    }

    attr = JXG.copyAttributes(attributes, board.options, 'integral');
    p = board.create('curve', [[0],[0]], attr);

    // dump stuff
    pa_on_curve.dump = false;
    pa_on_axis.dump = false;

    pb_on_curve.dump = false;
    pb_on_axis.dump = false;

    p.elType = 'integral';
    p.parents = [curve.id, interval];
    p.subs = {
        curveLeft: pa_on_curve,
        baseLeft: pa_on_axis,
        curveRight: pb_on_curve,
        baseRight: pb_on_axis
    };

    if (attr.withLabel) {
        p.subs.label = t;
    }

    /**
     * documented in JXG.Curve
     * @ignore
     */
    p.updateDataArray = function() {
        var x, y,
            i, left, right;

        if(pa_on_axis.X() < pb_on_axis.X()) {
            left = pa_on_axis.X();
            right = pb_on_axis.X();
        } else {
            left = pb_on_axis.X();
            right = pa_on_axis.X();
        }

        x = [left, left];
        y = [0, curve.Y(left)];

        for(i=0; i < curve.numberPoints; i++) {
            if( (left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right) ) {
                x.push(curve.points[i].usrCoords[1]);
                y.push(curve.points[i].usrCoords[2]);
            }
        }
        x.push(right);
        y.push(curve.Y(right));
        x.push(right);
        y.push(0);

        x.push(left); // close the curve
        y.push(0);

        this.dataX = x;
        this.dataY = y;
    };
    pa_on_curve.addChild(p);
    pb_on_curve.addChild(p);

    /**
     * The point on the axis initially corresponding to the lower value of the interval.
     * @memberOf Integral.prototype
     * @name baseLeft
     * @type JXG.Point
     */
    p.baseLeft = pa_on_axis;

    /**
     * The point on the axis initially corresponding to the higher value of the interval.
     * @memberOf Integral.prototype
     * @name baseRight
     * @type JXG.Point
     */
    p.baseRight = pb_on_axis;

    /**
     * The glider on the curve corresponding to the lower value of the interval.
     * @memberOf Integral.prototype
     * @name curveLeft
     * @type Glider
     */
    p.curveLeft = pa_on_curve;

    /**
     * The glider on the axis corresponding to the higher value of the interval.
     * @memberOf Integral.prototype
     * @name curveRight
     * @type Glider
     */
    p.curveRight = pb_on_curve;

    /**
     * documented in GeometryElement
     * @ignore
     */
    p.label = {
        content: t
    };

    return p;
};

/**
 * @class This element is used to visualize the locus of a given dependent point.
 * @pseudo
 * @description The locus element is used to visualize the curve a given point describes.
 * @constructor
 * @name Locus
 * @type JXG.Curve
 * @augments JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Point} p The constructed curve is the geometric locus of the given point.
 * @example
 *  // This examples needs JXG.Server up and running, otherwise it won't work.
 *  p1 = board.create('point', [0, 0]);
 *  p2 = board.create('point', [6, -1]);
 *  c1 = board.create('circle', [p1, 2]);
 *  c2 = board.create('circle', [p2, 1.5]);
 *  g1 = board.create('glider', [6, 3, c1]);
 *  c3 = board.create('circle', [g1, 4]);
 *  g2 = board.create('intersection', [c2,c3,0]);
 *  m1 = board.create('midpoint', [g1,g2]);
 *  loc = board.create('locus', [m1], {strokeColor: 'red'});
 * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *  lcex_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true});
 *  lcex_p1 = lcex_board.create('point', [0, 0]);
 *  lcex_p2 = lcex_board.create('point', [6, -1]);
 *  lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]);
 *  lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]);
 *  lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]);
 *  lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]);
 *  lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]);
 *  lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]);
 *  lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'});
 * </script><pre>
 */
JXG.createLocus = function(board, parents, attributes) {
    var c, p;

    if(JXG.isArray(parents) && parents.length == 1 && parents[0].elementClass == JXG.OBJECT_CLASS_POINT) {
        p = parents[0];
    } else {
        throw new Error("JSXGraph: Can't create locus with parent of type other than point." +
                        "\nPossible parent types: [point]");
    }

    c = board.create('curve', [[null], [null]], attributes);
    c.dontCallServer = false;

    c.elType = 'locus';
    c.parents = [p.id];

    /**
     * should be documented in JXG.Curve
     * @ignore
     */
    c.updateDataArray = function () {
        if(c.board.mode > 0)
            return;

        var spe = JXG.Math.Symbolic.generatePolynomials(board, p, true).join('|');
        if(spe === c.spe)
                return;

        c.spe = spe;

        var cb = function(x, y, eq, t) {
                c.dataX = x;
                c.dataY = y;

                /**
                 * The implicit definition of the locus.
                 * @memberOf Locus.prototype
                 * @name eq
                 * @type String
                 */
                c.eq = eq;

                /**
                 * The time it took to calculate the locus
                 * @memberOf Locus.prototype
                 * @name ctime
                 * @type Number
                 */
                c.ctime = t;

                // convert equation and use it to build a generatePolynomial-method
                c.generatePolynomial = (function(equations) {
                    return function(point) {
                        var x = '(' + point.symbolic.x + ')',
                            y = '(' + point.symbolic.y + ')',
                            res = [], i;

                        for(i=0; i<equations.length; i++)
                            res[i] = equations[i].replace(/\*\*/g, '^').replace(/x/g, x).replace(/y/g, y);

                        return res;
                    }
                })(eq);
            },
            data = JXG.Math.Symbolic.geometricLocusByGroebnerBase(board, p, cb);

        cb(data.datax, data.datay, data.polynomial, data.exectime);
    };
    return c;
};


/**
 * @class Creates a grid to support the user with element placement.
 * @pseudo
 * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method
 * draws such a grid on the given board. It uses options given in {@link JXG.Options#grid}. This method does not
 * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set
 * to true.
 * @parameter None.
 * @constructor
 * @name Grid
 * @type JXG.Curve
 * @augments JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @example
 * grid = board.create('grid', []);
 * </pre><div id="a9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 * (function () {
 *  board = JXG.JSXGraph.initBoard('a9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
 *  grid = board.create('grid', []);
 * })();
 * </script><pre>
 */
JXG.createGrid = function (board, parents, attributes) {
    var c, attr;

    attr = JXG.copyAttributes(attributes, board.options, 'grid');
    c = board.create('curve', [[null], [null]], attr);

    c.elType = 'grid';
    c.parents = [];
    c.type = JXG.OBJECT_TYPE_GRID;

    c.updateDataArray = function () {
        var gridX = this.visProp.gridx,
            gridY = this.visProp.gridy,
            topLeft = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0, 0], board),
            bottomRight = new JXG.Coords(JXG.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board),
            i;
        //horizontal = [[], []], vertical = [[], []];

        //
        //      |         |         |
        //  ----+---------+---------+-----
        //      |        /|         |
        //      |    gridY|     <---+------   Grid Cell
        //      |        \|         |
        //  ----+---------+---------+-----
        //      |         |\ gridX /|
        //      |         |         |
        //
        // uc: usercoordinates
        //
        // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high.
        // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it
        // is absolutely not user friendly when it comes to use it as an API interface.
        // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i
        // had to refactor these methods:
        //
        //  DONE JXG.Board.calculateSnapSizes (init p1, p2)
        //  DONE JXG.GeonextReader.readGeonext (init gridX, gridY)
        //

        board.options.grid.hasGrid = true;

        topLeft.setCoordinates(JXG.COORDS_BY_USER, [Math.floor(topLeft.usrCoords[1] / gridX) * gridX, Math.ceil(topLeft.usrCoords[2] / gridY) * gridY]);
        bottomRight.setCoordinates(JXG.COORDS_BY_USER, [Math.ceil(bottomRight.usrCoords[1] / gridX) * gridX, Math.floor(bottomRight.usrCoords[2] / gridY) * gridY]);

        c.dataX = [];
        c.dataY = [];

        // start with the horizontal grid:
        for (i = topLeft.usrCoords[2]; i > bottomRight.usrCoords[2] - gridY; i -= gridY) {
            c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN);
            c.dataY.push(i, i, NaN);
        }

        // build vertical grid
        for (i = topLeft.usrCoords[1]; i < bottomRight.usrCoords[1] + gridX; i += gridX) {
            c.dataX.push(i, i, NaN);
            c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN);
        }

    };

    // we don't care about highlighting so we turn it off completely to save a lot of
    // time on every mouse move
    c.hasPoint = function () {
        return false;
    };

    board.grids.push(c);

    return c;
};

/**
 * @class Creates an area indicating the solution of a linear inequality.
 * @pseudo
 * @description Display the solution set of a linear inequality (less than or equal to).
 * @param {JXG.Line} l The area drawn will be the area below this line.
 * @constructor
 * @name Inequality
 * @type JXG.Curve
 * @augments JXG.Curve
 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @example
 * p = board.create('point', [1, 3]);
 * q = board.create('point', [-2, -4]);
 * l = board.create('line', [p, q]);
 * ineq = board.create('inequality', [l]);
 * </pre><div id="2b703006-fd98-11e1-b79e-ef9e591c002e" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 * (function () {
 *  board = JXG.JSXGraph.initBoard('2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
 *  p = board.create('point', [1, 3]);
 *  q = board.create('point', [-2, -4]);
 *  l = board.create('line', [p, q]);
 *  ineq = board.create('inequality', [l]);
 * })();
 * </script><pre>
 */
JXG.createInequality = function (board, parents, attributes) {
    var f, a, attr;
    
    // TODO: documentation, special case line parallel to y axis, curve case
    
    attr = JXG.copyAttributes(attributes, board.options, 'inequality');
    if (parents[0].elementClass === JXG.OBJECT_CLASS_LINE) {
        a = board.create('curve', [[], []], attr);
        a.hasPoint = function () {
            return false
        };
        a.updateDataArray = function () {
            var bb = board.getBoundingBox(),
                factor = attr.inverse ? -1 : 1,
                expansion = 1.5,
                w = expansion*Math.max(bb[2] - bb[0], bb[1] - bb[3]),
                // this will be the height of the area. We mustn't rely upon the board height because if we pan the view
                // such that the line is not visible anymore, the borders of the area will get visible in some cases.
                h,
                // fake a point (for Math.Geometry.perpendicular)
                dp = {coords: {usrCoords: [1, (bb[0] + bb[2])/2, attr.inverse ? bb[1] : bb[3]]}},
                
                slope1 = parents[0].stdform.slice(1),
                slope2 = slope1,
                
                i1, i2;

            if (slope1[1] > 0) {
                slope1 = JXG.Math.Statistics.multiply(slope1, -1);
                slope2 = slope1;
            }

            // calculate the area height = 2* the distance of the line to the point in the middle of the top/bottom border.
            h = expansion*Math.max(JXG.Math.Geometry.perpendicular(parents[0], dp, board)[0].distance(JXG.COORDS_BY_USER, dp.coords), w);
            h *= factor;
            
            // reuse dp
            dp = {coords: {usrCoords: [1, (bb[0] + bb[2])/2, (bb[1] + bb[3])/2]}};
            dp = JXG.Math.Geometry.perpendicular(parents[0], dp, board)[0].usrCoords;
            i1 = [1, dp[1] + slope1[1]*w, dp[2] - slope1[0]*w];
            i2 = [1, dp[1] - slope2[1]*w, dp[2] + slope2[0]*w];
            
            // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1)
            // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and
            // end up in i2.
            this.dataX = [i1[1], i1[1] + slope1[0]*h, i2[1] + slope2[0]*h, i2[1], i1[1]];
            this.dataY = [i1[2], i1[2] + slope1[1]*h, i2[2] + slope2[1]*h, i2[2], i1[2]];
        };
    } else {
        f = JXG.createFunction(parents[0]);
        if (!JXG.exists(f)) {
            throw new Error("JSXGraph: Can't create area with the given parents." +
                            "\nPossible parent types: [line], [function]");
        }
        
        // TODO
    }
    
    return a;
};


JXG.JSXGraph.registerElement('arrowparallel', JXG.createArrowParallel);
JXG.JSXGraph.registerElement('bisector', JXG.createBisector);
JXG.JSXGraph.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);
JXG.JSXGraph.registerElement('circumcircle', JXG.createCircumcircle);
JXG.JSXGraph.registerElement('circumcirclemidpoint', JXG.createCircumcircleMidpoint);
JXG.JSXGraph.registerElement('circumcenter', JXG.createCircumcircleMidpoint);
JXG.JSXGraph.registerElement('incenter', JXG.createIncenter);
JXG.JSXGraph.registerElement('incircle', JXG.createIncircle);
JXG.JSXGraph.registerElement('integral', JXG.createIntegral);
JXG.JSXGraph.registerElement('midpoint', JXG.createMidpoint);
JXG.JSXGraph.registerElement('mirrorpoint', JXG.createMirrorPoint);
JXG.JSXGraph.registerElement('normal', JXG.createNormal);
JXG.JSXGraph.registerElement('orthogonalprojection', JXG.createOrthogonalProjection);
JXG.JSXGraph.registerElement('parallel', JXG.createParallel);
JXG.JSXGraph.registerElement('parallelpoint', JXG.createParallelPoint);
JXG.JSXGraph.registerElement('perpendicular', JXG.createPerpendicular);
JXG.JSXGraph.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);
JXG.JSXGraph.registerElement('perpendicularsegment', JXG.createPerpendicularSegment);
JXG.JSXGraph.registerElement('reflection', JXG.createReflection);
JXG.JSXGraph.registerElement('locus', JXG.createLocus);
JXG.JSXGraph.registerElement('grid', JXG.createGrid);
JXG.JSXGraph.registerElement('inequality', JXG.createInequality);


/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview In this file the Text element is defined.
 */


/**
 * Construct and handle texts.
 * @class Text: On creation the GEONExT syntax
 * of <value>-terms 
 * are converted into JavaScript syntax.
 * The coordinates can be relative to the coordinates of an element "element".
 * @constructor
 * @return A new geometry element Text
 */
JXG.Text = function (board, content, coords, attributes) {
    this.constructor(board, attributes, JXG.OBJECT_TYPE_TEXT, JXG.OBJECT_CLASS_OTHER);

    var i;

    this.content = '';
    this.plaintext = '';

    this.isDraggable = false;
    this.needsSizeUpdate = false;

    if ((this.element = JXG.getRef(this.board, attributes.anchor))) {
        var anchor;
        if (this.visProp.islabel) {
            this.relativeCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [parseFloat(coords[0]), parseFloat(coords[1])], this.board);
        } else {
            this.relativeCoords = new JXG.Coords(JXG.COORDS_BY_USER, [parseFloat(coords[0]), parseFloat(coords[1])], this.board);
        }
        this.element.addChild(this);
        
        this.X = function () {
            var sx, coords, anchor;

            if (this.visProp.islabel) {
                sx =  parseFloat(this.visProp.offset[0]);
                anchor = this.element.getLabelAnchor();
                coords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [sx + this.relativeCoords.scrCoords[1] + anchor.scrCoords[1], 0], this.board);
                
                return coords.usrCoords[1];
            } else {
                anchor = this.element.getTextAnchor();
                
                return this.relativeCoords.usrCoords[1] + anchor.usrCoords[1];
            }
        };
        
        this.Y = function () {
            var sy, coords, anchor;
            
            if (this.visProp.islabel) {
                sy = -parseFloat(this.visProp.offset[1]);
                anchor = this.element.getLabelAnchor();
                coords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0, sy + this.relativeCoords.scrCoords[2] + anchor.scrCoords[2]], this.board);

                return coords.usrCoords[2];
            } else {
                anchor = this.element.getTextAnchor();
                
                return this.relativeCoords.usrCoords[2] + anchor.usrCoords[2];
            }
        };

        this.coords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0,0], this.board);
        this.isDraggable = true;
    } else {
        if (JXG.isNumber(coords[0]) && JXG.isNumber(coords[1])) {
            this.isDraggable = true;
        }
        this.X = JXG.createFunction(coords[0], this.board, null, true);
        this.Y = JXG.createFunction(coords[1], this.board, null, true);

        this.coords = new JXG.Coords(JXG.COORDS_BY_USER, [this.X(),this.Y()], this.board);
    }
    this.Z = JXG.createFunction(1.0, this.board, '');

    this.size = [1.0, 1.0];

    this.id = this.board.setId(this, 'T');
    this.board.renderer.drawText(this);

    this.setText(content);
    this.updateSize();

    if(!this.visProp.visible) {
        this.board.renderer.hide(this);
    }
    
    if (typeof this.content === 'string') {
        this.notifyParents(this.content);
    }

    this.elType = 'text';

    this.methodMap = JXG.deepCopy(this.methodMap, {
        setText: 'setTextJessieCode',
        free: 'free',
        move: 'setCoords'
    });

    return this;
};
JXG.Text.prototype = new JXG.GeometryElement();

JXG.extend(JXG.Text.prototype, /** @lends JXG.Text.prototype */ {
    /**
     * @private
     * Test if the the screen coordinates (x,y) are in a small stripe 
     * at the left side or at the right side of the text.
     * Sensitivity is set in this.board.options.precision.hasPoint.
     * @param {Number} x
     * @param {Number} y 
     * @return {Boolean} 
     */
    hasPoint: function (x, y) {
        var lft, rt, top, bot,
            r = this.board.options.precision.hasPoint;
            
        if (this.visProp.anchorx === 'right') {
            lft = this.coords.scrCoords[1] - this.size[0];
        } else if (this.visProp.anchorx === 'middle') {
            lft = this.coords.scrCoords[1] - 0.5*this.size[0];
        } else { 
            lft = this.coords.scrCoords[1];
        }
        rt = lft + this.size[0];

        if (this.visProp.anchory === 'top') {
            bot = this.coords.scrCoords[2] + this.size[1];
        } else if (this.visProp.anchorx === 'middle') {
            bot = this.coords.scrCoords[2] + 0.5 * this.size[1];
        } else { 
            bot = this.coords.scrCoords[2];
        }
        top = bot - this.size[1];
        
        return (y >= top-r && y <= bot + r)
                && ((x >= lft - r  && x <= lft + 2*r) 
                    ||
                    (x >= rt - 2*r && x <= rt + r)
                   );
    },

    /**
     * Defines new content. This is used by {@link JXG.Text#setTextJessieCode} and {@link JXG.Text#setText}. This is required because
     * JessieCode needs to filter all Texts inserted into the DOM and thus has to replace setText by setTextJessieCode.
     * @param text
     * @return {JXG.Text}
     * @private
     */
    _setText: function (text) {
        this.needsSizeUpdate = false;
        
        if (typeof text === 'function') {
            this.updateText = function() { this.plaintext = text(); };
            this.needsSizeUpdate = true;
        } else {
            if (JXG.isNumber(text)) {
                this.content = (text).toFixed(this.visProp.digits);
            } else {
                if (this.visProp.useasciimathml) {
                    this.content = "'`" + text + "`'";              // Convert via ASCIIMathML
                    this.needsSizeUpdate = true;
                } else {
                    this.content = this.generateTerm(text);   // Converts GEONExT syntax into JavaScript string
                }
            }
            this.updateText = new Function('this.plaintext = ' + this.content + '; ');
        }

        this.updateText();                    // First evaluation of the string.
                                              // Needed for display='internal' and Canvas
        this.prepareUpdate().update().updateRenderer();

        return this;
    },

    /**
     * Defines new content but converts &lt; and &gt; to HTML entities before updating the DOM.
     * @param {String|function} text
     */
    setTextJessieCode: function (text) {
        var s;

        this.visProp.castext = text;

        if (typeof text === 'function') {
            s = function () {
                return text().replace(/</g, '&lt;').replace(/>/g, '&gt;');
            };
        } else {
            if (JXG.isNumber(text)) {
                s = text;
            } else {
                s = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
            }
        }
        
        return this._setText(s);
    },

    /**
     * Defines new content.
     * @param {String|function} text
     * @return {JXG.Text} Reference to the text object.
     */
    setText: function(text) {
        this._setText(text);
    },
    
    /**
     * Recompute the width and the height of the text box.
     * Update array this.size with pixel values.
     * The result may differ from browser to browser
     * by some pixels.
     * In IE and canvas we use a very crude estimation of the dimensions of
     * the textbox. 
     * In JSXGraph this.size is necessary for applying rotations in IE and
     * for aligning text.
     */
    updateSize: function () {
        var tmp;

        if (typeof document === 'undefined') {
            return this;
        }

        if (this.visProp.display=='html' && this.board.renderer.type !== 'vml' && this.board.renderer.type !== 'no') {
            this.size = [this.rendNode.offsetWidth, this.rendNode.offsetHeight];
        } else if (this.visProp.display === 'internal' && this.board.renderer.type === 'svg') {
            try {
                tmp = this.rendNode.getBBox();          // getBBox broken in FF 13? No.
                this.size = [tmp.width, tmp.height];
            } catch (e) {
            }
        } else if (this.board.renderer.type === 'vml' || (this.visProp.display === 'internal' && this.board.renderer.type === 'canvas')) {
            // Here comes a very crude estimation of the dimensions of the textbox. 
            this.size = [parseFloat(this.visProp.fontsize)*this.plaintext.length*0.45, parseFloat(this.visProp.fontsize)*0.9]
        }
        return this;
    },

    /**
     * Return the width of the text element.
     * @return {Array} [width, height] in pixel
     */
    getSize: function () {
        return this.size;
    },

    /**
     * Move the text to new coordinates.
     * @param {number} x
     * @param {number} y
     * @return {object} reference to the text object.
     */
    setCoords: function (x, y) {
        if (JXG.isArray(x) && x.length > 1) {
            y = x[1];
            x = x[0];
        }

        this.X = function() { return x; };
        this.Y = function() { return y; };
        this.coords.setCoordinates(JXG.COORDS_BY_USER, [x, y]);

        // this should be a local update, otherwise there might be problems
        // with the tick update routine resulting in orphaned tick labels
        this.prepareUpdate().update().updateRenderer();

        return this;
    },

    free: function () {
        this.X = JXG.createFunction(this.X(), this.board, '');
        this.Y = JXG.createFunction(this.Y(), this.board, '');

        this.isDraggable = true;
    },

    /**
     * Evaluates the text.
     * Then, the update function of the renderer
     * is called. 
     */
    update: function () {
        var anchor, sx, sy;

        if (this.needsUpdate) {
            this.updateCoords();
            this.updateText();
            if (this.needsSizeUpdate) {
                this.updateSize();
            }
            this.updateTransform();
        }
        return this;
    },

    /**
     * Updates the coordinates of the text element.
     */
    updateCoords: function () {
        this.coords.setCoordinates(JXG.COORDS_BY_USER, [this.X(), this.Y()]);
    },

    /**
     * The update function of the renderert
     * is called. 
     * @private
     */
    updateRenderer: function () {
        if (this.needsUpdate) {
            this.board.renderer.updateText(this);
            //this.updateSize();
            this.needsUpdate = false;
        }
        return this;
    },

    updateTransform: function () {
        var i;

        if (this.transformations.length==0) {
            return;
        }

        for (i = 0; i < this.transformations.length; i++) {
            this.transformations[i].update();
        }

        return this;
    },

    /**
     * Converts the GEONExT syntax of the <value> terms into JavaScript.
     * Also, all Objects whose name appears in the term are searched and
     * the text is added as child to these objects.
     * @private
     * @see Algebra
     * @see #geonext2JS.
     */
    generateTerm: function (contentStr) {
        var res,
            plaintext = '""',
            term;

        contentStr = contentStr || '';
        contentStr = contentStr.replace(/\r/g,''); 
        contentStr = contentStr.replace(/\n/g,''); 
        contentStr = contentStr.replace(/\"/g,'\\"'); 
        contentStr = contentStr.replace(/\'/g,"\\'"); 
        contentStr = contentStr.replace(/&amp;arc;/g,'&ang;'); 
        contentStr = contentStr.replace(/<arc\s*\/>/g,'&ang;'); 
        contentStr = contentStr.replace(/<sqrt\s*\/>/g,'&radic;'); 

        // Convert GEONExT syntax into  JavaScript syntax
        var i;

        i = contentStr.indexOf('<value>');
        var j = contentStr.indexOf('</value>');
        if (i>=0) {
            this.needsSizeUpdate = true;
            while (i>=0) {
                plaintext += ' + "'+ JXG.GeonextParser.replaceSub(JXG.GeonextParser.replaceSup(contentStr.slice(0,i))) + '"';
                term = contentStr.slice(i+7,j);
                res = JXG.GeonextParser.geonext2JS(term, this.board);
                res = res.replace(/\\"/g,'"');
                res = res.replace(/\\'/g,"'");

                if (res.indexOf('toFixed')<0) {  // GEONExT-Hack: apply rounding once only.  
                    if (JXG.isNumber( (JXG.bind(new Function('return '+res+';'), this))() )) {          // output of a value tag
                                                                                        // may also be a string
                        plaintext += '+('+ res + ').toFixed('+(this.visProp.digits)+')';
                    } else {
                        plaintext += '+('+ res + ')';   
                    }
                } else {
                    plaintext += '+('+ res + ')';
                }
                contentStr = contentStr.slice(j+8);
                i = contentStr.indexOf('<value>');
                j = contentStr.indexOf('</value>');
            }
        } //else {
        plaintext += ' + "' + JXG.GeonextParser.replaceSub(JXG.GeonextParser.replaceSup(contentStr)) + '"';
        //}
        plaintext = plaintext.replace(/<overline>/g,'<span style=text-decoration:overline>');
        plaintext = plaintext.replace(/<\/overline>/g,'</span>');
        plaintext = plaintext.replace(/<arrow>/g,'<span style=text-decoration:overline>');
        plaintext = plaintext.replace(/<\/arrow>/g,'</span>');

        plaintext = plaintext.replace(/&amp;/g,'&'); // This should replace &amp;pi; by &pi;
        return plaintext;
    },

    /**
     * Finds dependencies in a given term and notifies the parents by adding the
     * dependent object to the found objects child elements.
     * @param {String} content String containing dependencies for the given object.
     * @private
     */
    notifyParents: function (content) {
        var res = null;

        do {
            var search = /<value>([\w\s\*\/\^\-\+\(\)\[\],<>=!]+)<\/value>/;
            res = search.exec(content);
            if (res!=null) {
                JXG.GeonextParser.findDependencies(this,res[1],this.board);
                content = content.substr(res.index);
                content = content.replace(search,'');
            }
        } while (res!=null);
        return this;
    },

    bounds: function () {
        var c = this.coords.usrCoords;

        return this.visProp.islabel ? [0, 0, 0, 0] : [c[1], c[2]+this.size[1], c[1]+this.size[0], c[2]];
    },
    
    /**
     * Sets x and y coordinate of the text.
     * @param {number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinates in screen/user units
     * @param {Array} oldcoords previous coordinates in screen/user units
     */
    setPositionDirectly: function (method, coords, oldcoords) {
        var c = new JXG.Coords(method, coords, this.board),
            oldc = new JXG.Coords(method, oldcoords, this.board),
            dc,  v;
            
        if (this.relativeCoords) {
            if (this.visProp.islabel) {
                dc = JXG.Math.Statistics.subtract(c.scrCoords, oldc.scrCoords);        
                this.relativeCoords.scrCoords[1] += dc[1];
                this.relativeCoords.scrCoords[2] += dc[2];
            } else {
                dc = JXG.Math.Statistics.subtract(c.usrCoords, oldc.usrCoords);        
                this.relativeCoords.usrCoords[1] += dc[1];
                this.relativeCoords.usrCoords[2] += dc[2];
            }
        } else {
            dc = JXG.Math.Statistics.subtract(c.usrCoords, oldc.usrCoords);    
            v = [this.Z(), this.X(), this.Y()];            
            this.X = JXG.createFunction(v[1]+dc[1], this.board, '');
            this.Y = JXG.createFunction(v[2]+dc[2], this.board, '');
        }

        return this;
    }
    
});

/**
 * @class This element is used to provide a constructor for text, which is just a wrapper for element {@link Text}. 
 * @pseudo
 * @description
 * @name Text
 * @augments JXG.GeometryElement
 * @constructor
 * @type JXG.Text
 *
 * @param {number,function_number,function_String,function} x,y,str Parent elements for text elements.
 *                     <p>
 *                     x and y are the coordinates of the lower left corner of the text box. The position of the text is fixed, 
 *                     x and y are numbers. The position is variable if x or y are functions.
 *                     <p>
 *                     The text to display may be given as string or as function returning a string.
 *
 * There is the attribute 'display' which takes the values 'html' or 'internal'. In case of 'html' a HTML division tag is created to display
 * the text. In this case it is also possible to use ASCIIMathML. Incase of 'internal', a SVG or VML text element is used to display the text.
 * @see JXG.Text
 * @example
 * // Create a fixed text at position [0,1].
 *   var t1 = board.create('text',[0,1,"Hello World"]); 
 * </pre><div id="896013aa-f24e-4e83-ad50-7bc7df23f6b7" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var t1_board = JXG.JSXGraph.initBoard('896013aa-f24e-4e83-ad50-7bc7df23f6b7', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
 *   var t1 = t1_board.create('text',[0,1,"Hello World"]);
 * </script><pre>
 * @example
 * // Create a variable text at a variable position.
 *   var s = board.create('slider',[[0,4],[3,4],[-2,0,2]]);
 *   var graph = board.create('text', 
 *                        [function(x){ return s.Value();}, 1,
 *                         function(){return "The value of s is"+s.Value().toFixed(2);}
 *                        ]
 *                     );
 * </pre><div id="5441da79-a48d-48e8-9e53-75594c384a1c" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 *   var t2_board = JXG.JSXGraph.initBoard('5441da79-a48d-48e8-9e53-75594c384a1c', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
 *   var s = t2_board.create('slider',[[0,4],[3,4],[-2,0,2]]);
 *   var t2 = t2_board.create('text',[function(x){ return s.Value();}, 1, function(){return "The value of s is "+s.Value().toFixed(2);}]);
 * </script><pre>
 */
JXG.createText = function(board, parents, attributes) {
    var t, 
        attr = JXG.copyAttributes(attributes, board.options, 'text');

    // downwards compatibility
    attr.anchor = attr.parent || attr.anchor;

    t = new JXG.Text(board, parents[parents.length-1], parents, attr);

    if (typeof parents[parents.length-1] !== 'function') {
        t.parents = parents;
    }

    if (JXG.evaluate(attr.rotate) != 0 && attr.display=='internal') {
        t.addRotation(JXG.evaluate(attr.rotate));
    }

    return t;
};

JXG.JSXGraph.registerElement('text', JXG.createText);


/*
    Copyright 2008-2012
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.

*/

/**
 * @fileoverview In this file the geometry element Image is defined.
 */

/**
 * Construct and handle images
 * @class Image:
 * It inherits from @see GeometryElement.
 * @constructor
 */
JXG.Image = function (board, url, coords, size, attributes) {
    this.constructor(board, attributes, JXG.OBJECT_TYPE_IMAGE, JXG.OBJECT_CLASS_OTHER);

    this.initialCoords = new JXG.Coords(JXG.COORDS_BY_USER, coords, this.board);  // Still needed?

    if (!JXG.isFunction(coords[0]) && !JXG.isFunction(coords[1])) {
        this.isDraggable = true;
    }
    this.X = JXG.createFunction(coords[0],this.board,'');
    this.Y = JXG.createFunction(coords[1],this.board,'');
    this.Z = JXG.createFunction(1.0,this.board,'');
    this.W = JXG.createFunction(size[0],this.board,'');
    this.H = JXG.createFunction(size[1],this.board,'');
    this.coords = new JXG.Coords(JXG.COORDS_BY_USER, [this.X(),this.Y()], this.board);
    this.usrSize = [this.W(), this.H()];
    this.size = [Math.abs(this.usrSize[0]*board.unitX),Math.abs(this.usrSize[1]*board.unitY)];
    this.url = url;
    
    this.elType = 'image';
    
    // span contains the anchor point and the two vectors
    // spanning the image rectangle.
    this.span = [[this.Z(), this.X(), this.Y()], 
                  [this.Z(), this.W(), 0], 
                  [this.Z(), 0, this.H()]];

    this.parent = JXG.getRef(attributes.anchor);

    this.id = this.board.setId(this, 'Im');

    this.board.renderer.drawImage(this);
    if(!this.visProp.visible) {
       this.board.renderer.hide(this);
    }
    
};

JXG.Image.prototype = new JXG.GeometryElement;

JXG.extend(JXG.Image.prototype, /** @lends JXG.Image.prototype */ {

    /**
     * Checks whether (x,y) is over or near the image;
     * @param {int} x Coordinate in x direction, screen coordinates.
     * @param {int} y Coordinate in y direction, screen coordinates.
     * @return {Boolean} True if (x,y) is over the image, False otherwise.
     */
    hasPoint: function (x,y) {
        var len = this.transformations.length,
            dx, dy, r, // No transformations
            c, v, p, dot;  // Transformed image

        // Easy case: no transformation
        if (len==0) {
            dx = x-this.coords.scrCoords[1];
            dy = this.coords.scrCoords[2]-y;
            r = this.board.options.precision.hasPoint;
            if (dx>=-r && dx-this.size[0]<=r && 
                dy>=-r && dy-this.size[1]<=r) {
                    
                return true;
            } else {
                return false;
            }
        } else {
            // Image is transformed
            c = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board);
            // v is the vector from anchor poit to the drag point
            c = c.usrCoords;
            v = [c[0]-this.span[0][0], 
                 c[1]-this.span[0][1], 
                 c[2]-this.span[0][2]];
            dot = JXG.Math.innerProduct;   // shortcut
            
            // Project the drag point to the sides.
            p = dot(v, this.span[1]);
            if ( 0.0<=p && p <= dot(this.span[1], this.span[1])) {
                p = dot(v, this.span[2]);
                if ( 0.0<=p && p <= dot(this.span[2], this.span[2])) {
                    return true;
                }
            }
            return false;
        }
    },

    /**
     * Recalculate the coordinates of lower left corner and the width amd the height.
     * @private
     */
    update: function () {
        if (this.needsUpdate) {
            this.updateCoords();
            this.usrSize = [this.W(), this.H()];
            this.size = [Math.abs(this.usrSize[0]*this.board.unitX),Math.abs(this.usrSize[1]*this.board.unitY)];
            this.updateTransform();
            this.updateSpan();
        }
        return this;
    },

    /**
     * Send an update request to the renderer.
     */
    updateRenderer: function () {
        if (this.needsUpdate) {
            this.board.renderer.updateImage(this);
            this.needsUpdate = false;
        }
        return this;
    },

    updateTransform: function () {
        var i, len = this.transformations.length;
        if (len>0) {
            for (i=0; i<len; i++) {
                this.transformations[i].update();
            }
        }
        return this;
    },

    /**
     * Updates the coordinates of the top left corner of the image.
     */
    updateCoords: function () {
        this.coords.setCoordinates(JXG.COORDS_BY_USER, [this.X(), this.Y()]);
    },

    /**
     * Updates the size of the image.
     */
    updateSize: function () {
        this.coords.setCoordinates(JXG.COORDS_BY_USER, [this.W(), this.H()]);
    },
    
    /**
     * Update the anchor point of the image, i.e. the lower left corner
     * and the two vectors which span the rectangle.
     */
    updateSpan: function () {
        var i, j, len = this.transformations.length, v = [];

        if (len==0) {
            this.span = [[this.Z(), this.X(), this.Y()], 
                          [this.Z(), this.W(), 0], 
                          [this.Z(), 0, this.H()]];
        } else {
            // v contains the three defining corners of the rectangle/image
            v[0] = [this.Z(), this.X(), this.Y()];
            v[1] = [this.Z(), this.X()+this.W(), this.Y()];
            v[2] = [this.Z(), this.X(), this.Y()+this.H()];
            // Transform the three corners
            for (i=0; i<len; i++) {
                for (j=0; j<3; j++) {
                    v[j] = JXG.Math.matVecMult(this.transformations[i].matrix, v[j]);
                }
            }
            // Normalize the vectors
            for (j=0; j<3; j++) {
                v[j][1] /= v[j][0];
                v[j][2] /= v[j][0];
                v[j][0] /= v[j][0];
            }
            // Compute the two vectors spanning the rectangle
            // by subtracting the anchor point.
            for (j=1; j<3; j++) {
                v[j][0] -= v[0][0];
                v[j][1] -= v[0][1];
                v[j][2] -= v[0][2];
            }
            this.span = v;
        }
        return this;
    },

    addTransform: function (transform) {
        if (JXG.isArray(transform)) {
            for (var i=0;i<transform.length;i++) {
                this.transformations.push(transform[i]);
            }
        } else {
            this.transformations.push(transform);
        }
    },
    
    /**
     * Sets x and y coordinate of the image.
     * @param {number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.
     * @param {Array} coords coordinates in screen/user units of the mouse/touch position
     * @param {Array} oldcoords coordinates in screen/user units of the previous mouse/touch position
     * @returns {JXG.Image}
     */
    setPositionDirectly: function (method, coords, oldcoords) {
        var c = new JXG.Coords(method, coords, this.board),
            oldc = new JXG.Coords(method, oldcoords, this.board),
            dc,  v = [this.Z(), this.X(), this.Y()];
            
        dc = JXG.Math.Statistics.subtract(c.usrCoords, oldc.usrCoords);

        this.X = JXG.createFunction(v[1]+dc[1], this.board, '');
        this.Y = JXG.createFunction(v[2]+dc[2], this.board, '');

        return this;
    }
    
});

/**
 * @class Displays an image. 
 * @pseudo
 * @description Shows an image. The image can be supplied as an URL or an base64 encoded inline image 
 * like "data:image/png;base64, /9j/4AAQSkZJRgA..." or a function returning an URL: function(){ return 'xxx.png; }.
 * @constructor
 * @name Image
 * @type JXG.Image
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {String_Array_Array} url, [position of the top left vertice], [width,height] 
 * @example
 * var im = board.create('image', ['http://geonext.uni-bayreuth.de/fileadmin/geonext/design/images/logo.gif', [-3,1],[5,5]]);
 *
 * </pre><div id="9850cda0-7ea0-4750-981c-68bacf9cca57" style="width: 400px; height: 400px;"></div>
 * <script type="text/javascript">
 *   var image_board = JXG.JSXGraph.initBoard('9850cda0-7ea0-4750-981c-68bacf9cca57', {boundingbox: [-4, 4, 4, -4], axis: false, showcopyright: false, shownavigation: false});
 *   var image_im = image_board.create('image', ['http://jsxgraph.uni-bayreuth.de/distrib/images/uccellino.jpg', [-3,1],[5,5]]);
 * </script><pre>
 */
JXG.createImage = function(board, parents, attributes) {
    var url, attr, im;
    attr = JXG.copyAttributes(attributes, board.options, 'image');
    im = new JXG.Image(board, parents[0], parents[1], parents[2], attr);
    
    if (JXG.evaluate(attr.rotate) != 0) {
        im.addRotation(JXG.evaluate(attr.rotate));
    }
    
    return im;
};

JXG.JSXGraph.registerElement('image', JXG.createImage);


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview The geometry object Line is defined in this file. Line stores all
 * style and functional properties that are required to draw and move a line on
 * a board.
 */


/**
 * @class A slider can be used to choose values from a given range of numbers.
 * @pseudo
 * @description
 * @name Slider
 * @augments Glider
 * @constructor
 * @type JXG.Point
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {Array_Array_Array} start,end,data The first two arrays give the start and the end where the slider is drawn
 * on the board. The third array gives the start and the end of the range the slider operates as the first resp. the
 * third component of the array. The second component of the third array gives its start value.
 * @example
 * // Create a free point using affine euclidean coordinates
 * var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]);
 * </pre><div id="cfb51cde-2603-4f18-9cc4-1afb452b374d" style="width: 200px; height: 200px;"></div>
 * <script type="text/javascript">
 *   (function () {
 *     var board = JXG.JSXGraph.initBoard('cfb51cde-2603-4f18-9cc4-1afb452b374d', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
 *     var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]);
 *   })();
 * </script><pre>
 * @example
 * // Create a constrained point using anonymous function
 * var s = board.create('slider', [[1, 3], [3, 1], [1, 10, 50]], {snapWidth: 1});
 * </pre><div id="e17128e6-a25d-462a-9074-49460b0d66f4" style="width: 200px; height: 200px;"></div>
 * <script type="text/javascript">
 *   (function () {
 *     var board = JXG.JSXGraph.initBoard('e17128e6-a25d-462a-9074-49460b0d66f4', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
 *     var s = board.create('slider', [[1, 3], [3, 1], [1, 10, 50]], {snapWidth: 1});
 *   })();
 * </script><pre>
 */
JXG.createSlider = function(board, parents, attributes) {
    var pos0, pos1, smin, start, smax, sdiff, 
           p1, p2, l1, ticks, ti, startx, starty, p3, l2, n, t,
           withText, withTicks, snapWidth, attr, precision;

    pos0 = parents[0];
    pos1 = parents[1];
    smin = parents[2][0];
    start = parents[2][1];
    smax = parents[2][2];
    sdiff = smax -smin;

    attr = JXG.copyAttributes(attributes, board.options, 'slider');
    withTicks = attr['withticks'];
    withText = attr['withlabel'];
    snapWidth = attr['snapwidth'];
    precision = attr['precision'];
    
    attr = JXG.copyAttributes(attributes, board.options, 'slider', 'point1');
    p1 = board.create('point', pos0,  attr);

    attr = JXG.copyAttributes(attributes, board.options, 'slider', 'point2');
    p2 = board.create('point', pos1,  attr);
    board.create('group',[p1,p2]);
    
    attr = JXG.copyAttributes(attributes, board.options, 'slider', 'baseline');
    l1 = board.create('segment', [p1,p2], attr);

    // this is required for a correct projection of the glider onto the segment below
    l1.updateStdform();
    
    if (withTicks) {
        attr = JXG.copyAttributes(attributes, board.options, 'slider', 'ticks');
        ticks  = 2;
        ti = board.create('ticks', [l1, p2.Dist(p1)/ticks], attr);
    }

    startx = pos0[0]+(pos1[0]-pos0[0])*(start-smin)/(smax-smin);
    starty = pos0[1]+(pos1[1]-pos0[1])*(start-smin)/(smax-smin);

    attr = JXG.copyAttributes(attributes, board.options, 'slider');
    // overwrite this in any case; the sliders label is a special text element, not the gliders label.
    attr.withLabel = false;
    p3 = board.create('glider', [startx, starty, l1], attr);   // gliders set snapwidth=-1 by default (i.e. deactivate them)
    p3.setProperty({snapwidth:snapWidth});

    attr = JXG.copyAttributes(attributes, board.options, 'slider', 'highline');
    l2 = board.create('segment', [p1,p3],  attr);
                 
    p3.Value = function() {
        return p3.visProp.snapwidth === -1 ? this.position*sdiff+smin : Math.round((this.position*sdiff+smin)/this.visProp.snapwidth)*this.visProp.snapwidth;
    };

    p3.methodMap = JXG.deepCopy(p3.methodMap, {
        Value: 'Value'
    });

    /**
     * End value of the slider range.
     * @memberOf Slider.prototype
     * @name _smax
     * @type Number
     */
    p3._smax = smax;

    /**
     * Start value of the slider range.
     * @memberOf Slider.prototype
     * @name _smin
     * @type Number
     */
    p3._smin = smin;

    if (withText) {
        if (attributes['name'] && attributes['name']!='') {
            n = attributes['name'] + ' = ';
        } else {
            n = '';
        }
        attr = JXG.copyAttributes(attributes, board.options, 'slider', 'label');
        t = board.create('text', [function(){return (p2.X()-p1.X())*0.05+p2.X();},
                                  function(){return (p2.Y()-p1.Y())*0.05+p2.Y();},
                                  function(){return n+(p3.Value()).toFixed(precision);}],
                         attr); 
        /**
         * The text element to the right of the slider, indicating its current value.
         * @memberOf Slider.prototype
         * @name label
         * @type JXG.Text
         */
        p3.label.content = t;
    }

    /**
     * Start point of the base line.
     * @memberOf Slider.prototype
     * @name point1
     * @type JXG.Point
     */
    p3.point1 = p1;
    /**
     * End point of the base line.
     * @memberOf Slider.prototype
     * @name point2
     * @type JXG.Point
     */
    p3.point2 = p2;

    /**
     * The baseline the glider is bound to.
     * @memberOf Slider.prototype
     * @name baseline
     * @type JXG.Line
     */
    p3.baseline = l1;
    /**
     * A line on top of the baseline, indicating the slider's progress.
     * @memberOf Slider.prototype
     * @name highline
     * @type JXG.Line
     */
    p3.highline = l2;

    if (withTicks) {
        /**
         * Ticks give a rough indication about the slider's current value.
         * @memberOf Slider.prototype
         * @name ticks
         * @type JXG.Ticks
         */
        p3.ticks = ti;
    }

    // override the point's remove method to ensure the removal of all elements
    p3.remove = function () {
        if (withText) {
            board.removeObject(t);
        }
        
        board.removeObject(l2);

        if (withTicks) {
            l1.removeTicks(ti);
        }

        board.removeObject(l1);
        board.removeObject(p2);
        board.removeObject(p1);


        JXG.Point.prototype.remove.call(p3);
    };

    p1.dump = false;
    p2.dump = false;
    l1.dump = false;
    l2.dump = false;

    p3.elType = 'slider';
    p3.parents = parents;
    p3.subs = {
        point1: p1,
        point2: p2,
        baseLine: l1,
        highLine: l2
    };

    if (withTicks) {
        ti.dump = false;
        p3.subs.ticks = ti;
    }
    
    return p3;
};    

JXG.JSXGraph.registerElement('slider', JXG.createSlider);


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * Chart plotting
 */
JXG.Chart = function(board, parents, attributes) {
    this.constructor(board, attributes);

    var x, y, i, c, style, len;

    if (!JXG.isArray(parents) || parents.length === 0) {
        throw new Error('JSXGraph: Can\'t create a chart without data');
    }

    /**
     * Contains pointers to the various subelements of the chart.
     */
    this.elements = [];

    if (JXG.isNumber(parents[0])) {
        // parents looks like [a,b,c,..]
        // x has to be filled

        y = parents;
        x = [];
        for (i=0;i<y.length;i++) {
            x[i] = i+1;
        }
    } else if (parents.length === 1 && JXG.isArray(parents[0])) {
        // parents looks like [[a,b,c,..]]
        // x has to be filled

        y = parents[0];
        x = [];

        len = JXG.evaluate(y).length;
        for (i = 0; i < len; i++) {
            x[i] = i+1;
        }
    } else if (parents.length === 2) {
        // parents looks like [[x0,x1,x2,...],[y1,y2,y3,...]]
        len = Math.min(parents[0].length, parents[1].length);
        x = parents[0].slice(0, len);
        y = parents[1].slice(0, len);
    }

    if (JXG.isArray(y) && y.length === 0) {
        throw new Error('JSXGraph: Can\'t create charts without data.');
    }

    // does this really need to be done here? this should be done in createChart and then
    // there should be an extra chart for each chartstyle
    style = attributes.chartstyle.replace(/ /g,'').split(',');
    for (i = 0; i < style.length; i++) {
        switch (style[i]) {
            case 'bar':
                c = this.drawBar(board, x, y, attributes);
                break;
            case 'line':
                c = this.drawLine(board, x, y, attributes);
                break;
            case 'fit':
                c = this.drawFit(board, x, y, attributes);
                break;
            case 'spline':
                c = this.drawSpline(board, x, y, attributes);
                break;
            case 'pie':
                c = this.drawPie(board, y, attributes);
                break;
            case 'point':
                c = this.drawPoints(board, x, y, attributes);
                break;
            case 'radar':
                c = this.drawRadar(board, parents, attributes);
                break;
        }
        this.elements.push(c);
    }
    this.id = this.board.setId(this, 'Chart');
    
    return this.elements;
};
JXG.Chart.prototype = new JXG.GeometryElement;

JXG.extend(JXG.Chart.prototype, /** @lends JXG.Chart.prototype */ {

    drawLine: function(board, x, y, attributes) {
        // we don't want the line chart to be filled
        attributes.fillcolor = 'none';
        attributes.highlightfillcolor = 'none';

        return board.create('curve', [x, y], attributes);
    },

    drawSpline: function(board, x, y, attributes) {
        // we don't want the spline chart to be filled
        attributes.fillColor = 'none';
        attributes.highlightfillcolor = 'none';

        return board.create('spline', [x, y], attributes);
    },

    drawFit: function(board, x, y, attributes) {
        var deg = attributes.degree;

        deg = (!JXG.exists(deg) || parseInt(deg) == NaN || parseInt(deg) < 1) ? 1 : parseInt(deg),

        // never fill
        attributes.fillcolor = 'none';
        attributes.highlightfillcolor = 'none';

        return board.create('functiongraph', [JXG.Math.Numerics.regressionPolynomial(deg, x, y)], attributes);
    },

    drawBar: function(board, x, y, attributes) {
        var i,pols = [], strwidth, fill, fs, text,
            w, xp0, xp1, xp2, yp, colors, p = [],
            hiddenPoint = {
                fixed: true,
                withLabel: false,
                visible: false,
                name: ''
            };
        
        if (!JXG.exists(attributes.fillopacity)) {
            attributes.fillopacity = 0.6;
        }

        // Determine the width of the bars
        if (attributes && attributes.width) {  // width given
            w = attributes.width;
        } else {
            if (x.length <= 1) {
                w = 1;
            } else {
                // Find minimum distance between to bars.
                w = x[1]-x[0];
                for (i = 1; i < x.length-1; i++) {
                    w = (x[i+1] - x[i] < w) ? x[i+1] - x[i] : w;
                }
            }
            w *=0.8;
        }

        fill = attributes.fillcolor;
        fs = parseFloat(board.options.text.fontSize);                 // TODO: handle fontSize attribute
        for (i = 0; i < x.length; i++) {
            if (isNaN(JXG.evaluate(x[i])) || isNaN(y[i])) {
                //continue;
            }
            if (JXG.isFunction(x[i])) {
                xp0 = function() { return x[i]()-w*0.5; };
                xp1 = function() { return x[i](); };
                xp2 = function() { return x[i]()+w*0.5; };
            } else {
                xp0 = x[i]-w*0.5;
                xp1 = x[i];
                xp2 = x[i]+w*0.5;
            }
            yp = y[i];
            if (attributes.dir == 'horizontal') {  // horizontal bars
                p[0] = board.create('point',[0,xp0], hiddenPoint);
                p[1] = board.create('point',[yp,xp0], hiddenPoint);
                p[2] = board.create('point',[yp,xp2], hiddenPoint);
                p[3] = board.create('point',[0,xp2], hiddenPoint);

                if ( JXG.exists(attributes.labels) && JXG.exists(attributes.labels[i]) ) {
                    strwidth = attributes.labels[i].toString().length;
                    strwidth = 2.0*strwidth*fs/board.unitX;
                    if (yp>=0) {
                        yp += fs*0.5/board.unitX;   // Static offset for label
                    } else {
                        yp -= fs*strwidth/board.unitX;   // Static offset for label
                    }
                    xp1 -= fs*0.2/board.unitY;
                    text = board.create('text',[yp,xp1,attributes.labels[i]],attributes);
                }
            } else { // vertical bars
                p[0] = board.create('point',[xp0,0], hiddenPoint);
                p[1] = board.create('point',[xp0,yp], hiddenPoint);
                p[2] = board.create('point',[xp2,yp], hiddenPoint);
                p[3] = board.create('point',[xp2,0], hiddenPoint);
                if ( JXG.exists(attributes.labels) && JXG.exists(attributes.labels[i]) ) {
                    strwidth = attributes.labels[i].toString().length;
                    strwidth = 0.6*strwidth*fs/board.unitX;
                    if (yp>=0) {
                        yp += fs*0.5/board.unitY;   // Static offset for label
                    } else {
                        yp -= fs*1.0/board.unitY;   // Static offset for label
                    }
                    text = board.create('text',[xp1-strwidth*0.5, yp, attributes['labels'][i]],attributes);
                }
            }

            attributes.withlines = false;
            if(JXG.exists(attributes.colors) && JXG.isArray(attributes.colors)) {
                colors = attributes.colors;
                attributes.fillcolor = colors[i%colors.length];
            }
            pols[i] = board.create('polygon', p, attributes);
            if (JXG.exists(attributes.labels) && JXG.exists(attributes.labels[i])) {
                pols[i].text = text;
            }
        }

        return pols;
    },

    drawPoints: function(board, x, y, attributes) {
        var i,
            points = [],
            infoboxArray = attributes.infoboxarray;

        attributes.fixed = true;
        attributes.name = '';

        for (i = 0; i < x.length; i++) {
            attributes.infoboxtext = infoboxArray ? infoboxArray[i%infoboxArray.length] : false;
            points[i] = board.create('point', [x[i], y[i]], attributes);
        }

        return points;
    },

    drawPie: function(board, y, attributes) {
        var i,
            p = [],
            sector = [],
            s = JXG.Math.Statistics.sum(y),
            colorArray = attributes.colors,
            highlightColorArray = attributes.highlightcolors,
            labelArray = attributes.labels,
            r = attributes.radius || 4,
            radius = r,
            cent = attributes.center || [0,0],
            xc = cent[0],
            yc = cent[1],
            center,
            hiddenPoint = {
                fixed: true,
                withLabel: false,
                visible: false,
                name: ''
            };

        if (!JXG.isArray(labelArray)) {
            labelArray = [];
            for(i = 0; i < y.length; i++) {
                labelArray[i] = '';
            }
        }

        if (!JXG.isFunction(r)) {
            radius = function(){ return r; }
        }

        attributes.highlightonsector = attributes.highlightonsector || false;
        attributes.straightfirst = false;
        attributes.straightlast = false;

        center = board.create('point',[xc, yc], hiddenPoint);
        p[0] = board.create('point', [
            function () {
                return radius() + xc;
            },
            function () {
                return yc;
            }
        ], hiddenPoint);

        for (i = 0; i < y.length; i++) {
            p[i+1] = board.create('point', [
                (function(j) {
                    return function() {
                        var s, t = 0, i, rad;

                        for (i = 0; i <= j; i++) {
                            t += parseFloat(JXG.evaluate(y[i]));
                        }
                        s = t;
                        for (i = j + 1; i < y.length; i++) {
                            s += parseFloat(JXG.evaluate(y[i]));
                        }
                        rad = (s != 0) ? (2*Math.PI*t/s) : 0;

                        return radius()*Math.cos(rad)+xc;
                    };
                })(i),
                (function(j){
                    return function() {
                        var s, t = 0.0, i, rad;
                        for (i = 0; i <= j ;i++) {
                            t += parseFloat(JXG.evaluate(y[i]));
                        }
                        s = t;
                        for (i = j + 1; i < y.length; i++) {
                            s += parseFloat(JXG.evaluate(y[i]));
                        }
                        rad = (s != 0) ? (2*Math.PI*t/s) : 0;

                        return radius()*Math.sin(rad)+yc;
                    };
                })(i)
            ], hiddenPoint);

            attributes.name = labelArray[i];
            attributes.withlabel = attributes.name != '';
            attributes.fillcolor = colorArray && colorArray[i%colorArray.length];
            attributes.labelcolor = colorArray && colorArray[i%colorArray.length];
            attributes.highlightfillcolor = highlightColorArray && highlightColorArray[i%highlightColorArray.length];

            sector[i] = board.create('sector',[center,p[i],p[i+1]], attributes);

            if(attributes.highlightonsector) {
                sector[i].hasPoint = sector[i].hasPointSector; // overwrite hasPoint so that the whole sector is used for highlighting
            }
            if(attributes.highlightbysize) {
                sector[i].highlight = function() {
                    if (!this.highlighted) {
                        this.highlighted = true;

                        this.board.renderer.highlight(this);
                        var dx = - this.point1.coords.usrCoords[1] + this.point2.coords.usrCoords[1],
                            dy = - this.point1.coords.usrCoords[2] + this.point2.coords.usrCoords[2];

                        if(this.label.content != null) {
                            this.label.content.rendNode.style.fontSize = (2*this.label.content.visProp.fontsize) + 'px';
                            this.label.content.prepareUpdate().update().updateRenderer();
                        }

                        this.point2.coords = new JXG.Coords(JXG.COORDS_BY_USER, [
                            this.point1.coords.usrCoords[1]+dx*1.1,
                            this.point1.coords.usrCoords[2]+dy*1.1
                        ], this.board);
                        this.prepareUpdate().update().updateRenderer();
                    }
                };

                sector[i].noHighlight = function() {
                    if (this.highlighted) {
                        this.highlighted = false;
                        this.board.renderer.noHighlight(this);

                        var dx = -this.point1.coords.usrCoords[1] + this.point2.coords.usrCoords[1],
                            dy = -this.point1.coords.usrCoords[2] + this.point2.coords.usrCoords[2];

                        if(this.label.content != null) {
                            this.label.content.rendNode.style.fontSize = (this.label.content.visProp.fontsize*2) + 'px';
                            this.label.content.prepareUpdate().update().updateRenderer();
                        }

                        this.point2.coords = new JXG.Coords(JXG.COORDS_BY_USER, [
                            this.point1.coords.usrCoords[1]+dx/1.1,
                            this.point1.coords.usrCoords[2]+dy/1.1
                        ], this.board);
                        this.prepareUpdate().update().updateRenderer();
                    }
                };
            }

        }
        return {sectors:sector, points:p, midpoint:center}; //[0];  // Not enough! We need points, but this gives an error in board.setProperty.
    },

    /*
     * labelArray=[ row1, row2, row3 ]
     * paramArray=[ paramx, paramy, paramz ]
     * parents=[[x1, y1, z1], [x2, y2, z2], [x3, y3, z3]]
     */
    drawRadar: function(board, parents, attributes) {
        var i, j, paramArray, numofparams, maxes, mins,
            len = parents.length,
            la, pdata, ssa, esa, ssratio, esratio,
            sshifts, eshifts, starts, ends,
            labelArray, colorArray, highlightColorArray, radius, myAtts,
            cent, xc, yc, center, start_angle, rad, p, line, t,
            xcoord, ycoord, polygons, legend_position, circles,
            cla, clabelArray, ncircles, pcircles, angle, dr;

        if (len<=0) {
            JXG.debug("No data");
            return;
        }
        // labels for axes
        paramArray = attributes['paramarray'];
        if (!JXG.exists(paramArray)) {
            JXG.debug("Need paramArray attribute");
            return;
        }
        numofparams=paramArray.length;
        if (numofparams<=1) {
            JXG.debug("Need more than 1 param");
            return;
        }

        for(i=0; i<len; i++) {
            if (numofparams!=parents[i].length) {
                JXG.debug("Use data length equal to number of params (" + parents[i].length + " != " + numofparams + ")");
                return;
            }
        }
        maxes=new Array(numofparams);
        mins=new Array(numofparams);
        for(j=0; j<numofparams; j++) {
            maxes[j] = parents[0][j];
            mins[j] = maxes[j];
        }
        for(i=1; i<len; i++) {
            for(j=0;j<numofparams; j++) {
                if (parents[i][j]>maxes[j])
                    maxes[j] = parents[i][j];
                if (parents[i][j]<mins[j])
                    mins[j] = parents[i][j];
            }
        }

        la = new Array(len);
        pdata = new Array(len);
        for(i=0; i<len; i++) {
            la[i] = '';
            pdata[i] = [];
        }

        ssa = new Array(numofparams);
        esa = new Array(numofparams);

        // 0 <= Offset from chart center <=1
        ssratio = attributes.startshiftratio || 0.0;
        // 0 <= Offset from chart radius <=1
        esratio = attributes.endshiftratio || 0.0;

        for(i=0; i<numofparams; i++) {
            ssa[i] = (maxes[i]-mins[i])*ssratio;
            esa[i] = (maxes[i]-mins[i])*esratio;
        }

        // Adjust offsets per each axis
        sshifts = attributes.startshiftarray || ssa;
        eshifts = attributes.endshiftarray || esa;
        // Values for inner circle, minimums by default
        starts = attributes.startarray || mins;

        if (JXG.exists(attributes.start))
            for(i=0; i<numofparams; i++) starts[i] = attributes.start;
        // Values for outer circle, maximums by default
        ends = attributes.endarray || maxes;
        if (JXG.exists(attributes.end))
            for(i=0; i<numofparams; i++) ends[i] = attributes.end;

        if(sshifts.length != numofparams) {
            JXG.debug("Start shifts length is not equal to number of parameters");
            return;
        }
        if(eshifts.length != numofparams) {
            JXG.debug("End shifts length is not equal to number of parameters");
            return;
        }
        if(starts.length != numofparams) {
            JXG.debug("Starts length is not equal to number of parameters");
            return;
        }
        if(ends.length != numofparams) {
            JXG.debug("Ends length is not equal to number of parameters");
            return;
        }

        // labels for legend
        labelArray = attributes.labelarray || la;
        colorArray = attributes.colors;
        highlightColorArray = attributes.highlightcolors;
        radius = attributes.radius || 10;
        myAtts = {};
        if (!JXG.exists(attributes.highlightonsector)) {
            attributes.highlightonsector = false;
        }
        
        myAtts['name'] = attributes['name'];
        myAtts['id'] = attributes['id'];
        myAtts['strokewidth'] = attributes['strokewidth'] || 1;
        myAtts['polystrokewidth'] = attributes['polystrokewidth'] || 2*myAtts['strokewidth'];
        myAtts['strokecolor'] = attributes['strokecolor'] || 'black';
        myAtts['straightfirst'] = false;
        myAtts['straightlast'] = false;
        myAtts['fillcolor'] = attributes['fillColor'] || '#FFFF88';
        myAtts['fillopacity'] = attributes['fillOpacity'] || 0.4;
        myAtts['highlightfillcolor'] = attributes['highlightFillColor'] || '#FF7400';
        myAtts['highlightstrokecolor'] = attributes['highlightStrokeColor'] || 'black';
        myAtts['gradient'] = attributes['gradient'] || 'none';

        cent = attributes['center'] || [0,0];
        xc = cent[0];
        yc = cent[1];

        center = board.create('point',[xc,yc], {name:'', fixed:true, withlabel:false, visible:false});
        start_angle = Math.PI/2 - Math.PI/numofparams;
        if(attributes['startangle'] || attributes['startangle'] === 0)
            start_angle = attributes['startangle'];

        rad = start_angle;
        p = [];
        line = [];
        var get_anchor =  function() {
            var x1, x2, y1, y2,
                relCoords = this.visProp.label.offset.slice(0);
                
            x1 = this.point1.X();
            x2 = this.point2.X();
            y1 = this.point1.Y();
            y2 = this.point2.Y();
            if(x2<x1)
                relCoords[0] = -relCoords[0];
            if(y2<y1)
                relCoords[1] = -relCoords[1];

            this.setLabelRelativeCoords(relCoords);
            return new JXG.Coords(JXG.COORDS_BY_USER, [this.point2.X(),this.point2.Y()],this.board);
        };

        var get_transform = function(angle,i) {
            var t;
            var tscale;
            var trot;
            t = board.create('transform', [-(starts[i]-sshifts[i]), 0],{type:'translate'});
            tscale = board.create('transform', [radius/((ends[i]+eshifts[i])-(starts[i]-sshifts[i])), 1],{type:'scale'});
            t.melt(tscale);
            trot = board.create('transform', [angle],{type:'rotate'});
            t.melt(trot);
            return t;
        };

        for (i=0;i<numofparams;i++) {
            rad += 2*Math.PI/numofparams;
            xcoord = radius*Math.cos(rad)+xc;
            ycoord = radius*Math.sin(rad)+yc;

            p[i] = board.create('point',[xcoord,ycoord], {name:'',fixed:true,withlabel:false,visible:false});
            line[i] = board.create('line',[center,p[i]],
            {name:paramArray[i],
                strokeColor:myAtts['strokecolor'], 
                strokeWidth:myAtts['strokewidth'], 
                strokeOpacity:1.0,
                straightFirst:false, straightLast:false, withLabel:true,
                highlightStrokeColor:myAtts['highlightstrokecolor']
            });
            line[i].getLabelAnchor = get_anchor;
            t = get_transform(rad,i);

            for(j=0; j<parents.length; j++) {
                var data=parents[j][i];
                pdata[j][i] = board.create('point',[data,0], {name:'',fixed:true,withlabel:false,visible:false});
                pdata[j][i].addTransform(pdata[j][i], t);
            }
        }
        
        polygons = new Array(len);
        for(i=0;i<len;i++) {
            myAtts['labelcolor'] = colorArray && colorArray[i%colorArray.length];
            myAtts['strokecolor'] = colorArray && colorArray[i%colorArray.length];
            myAtts['fillcolor'] = colorArray && colorArray[i%colorArray.length];
            polygons[i] = board.create('polygon',pdata[i], {
                withLines:true,
                withLabel:false,
                fillColor:myAtts['fillcolor'],
                fillOpacity:myAtts['fillopacity'],
                highlightFillColor:myAtts['highlightfillcolor']
            });
            for(j=0;j<numofparams;j++) {
                polygons[i].borders[j].setProperty('strokecolor:' + colorArray[i%colorArray.length]);
                polygons[i].borders[j].setProperty('strokewidth:' + myAtts['polystrokewidth']);
            }
        }

        legend_position = attributes['legendposition'] || 'none';
        switch(legend_position) {
            case 'right':
                var lxoff = attributes['legendleftoffset'] || 2;
                var lyoff = attributes['legendtopoffset'] || 1;
                this.legend = board.create('legend', [xc+radius+lxoff,yc+radius-lyoff],
                {
                    labels: labelArray,
                    colors: colorArray
                });
                break;
            case 'none':
                break;
            default:
                JXG.debug('Unknown legend position');
        }

        circles = [];
        if (attributes['showcircles'] != false) {
            cla = [];
            for(i=0;i<6;i++)
                cla[i]=20*i;
            cla[0] = "0";
            clabelArray = attributes['circlelabelarray'] || cla;
            ncircles = clabelArray.length;
            if (ncircles<2) {alert("Too less circles"); return; }
            pcircles = [];
            angle=start_angle + Math.PI/numofparams;
            t = get_transform(angle,0);
            myAtts['fillcolor'] = 'none';
            myAtts['highlightfillcolor'] = 'none';
            myAtts['strokecolor'] = attributes['strokecolor'] || 'black';
            myAtts['strokewidth'] = attributes['circlestrokewidth'] || 0.5;
            myAtts['layer'] = 0;
            
            // we have ncircles-1 intervals between ncircles circles
            dr = (ends[0]-starts[0])/(ncircles-1);
            for(i=0;i<ncircles;i++) {
                pcircles[i] = board.create('point', [starts[0]+i*dr,0],
                    {name:clabelArray[i], size:0, fixed:true, withLabel:true, visible:true}
                    );
                pcircles[i].addTransform(pcircles[i],t);
                circles[i] = board.create('circle', [center,pcircles[i]], myAtts);
            }

        }
        this.rendNode = polygons[0].rendNode;
        return {circles:circles, lines:line, points:pdata, midpoint:center, polygons:polygons}; //[0];  // Not enough! We need points, but this gives an error in board.setProperty.
    },

    /**
     * Then, the update function of the renderer
     * is called.  Since a chart is only an abstract element,
     * containing other elements, this function is empty.
     */
    updateRenderer: function () { return this; },

    /**
     * Update of the defining points
     */
    update: function () {
        if (this.needsUpdate) {
            this.updateDataArray();
        }
        return this;
    },

    /**
     * For dynamic charts update
     * can be used to compute new entries
     * for the arrays this.dataX and
     * this.dataY. It is used in @see update.
     * Default is an empty method, can be overwritten
     * by the user.
     */
    updateDataArray: function () {}
});

JXG.createChart = function(board, parents, attributes) {

    if((parents.length == 1) && (typeof parents[0] == 'string')) {
        // todo: don't use document in here. let the user provide the dom node directly
        var table = document.getElementById(parents[0]),
            data, row, i, j, col, charts = [], w, x, showRows,
            originalWidth, name, strokeColor, fillColor, hStrokeColor, hFillColor, len, attr;
        if(JXG.exists(table)) {
            // extract the data
            attr = JXG.copyAttributes(attributes, board.options, 'chart');

            table = (new JXG.DataSource()).loadFromTable(parents[0], attr.withheaders, attr.withheaders);
            data = table.data;
            col = table.columnHeaders;
            row = table.rowHeaders;

            originalWidth = attr.width;
            name = attr.name;
            strokeColor = attr.strokecolor;
            fillColor = attr.fillcolor;
            hStrokeColor = attr.highlightstrokecolor;
            hFillColor = attr.highlightfillcolor;

            board.suspendUpdate();

            len = data.length;
            showRows = [];
            if (attr.rows && JXG.isArray(attr.rows)) {
                for(i=0; i<len; i++) {
                    for(j=0; j<attr.rows.length; j++) {
                        if((attr.rows[j] == i) || (attr.withheaders && attr.rows[j] == row[i])) {
                            showRows.push(data[i]);
                            break;
                        }
                    }
                }
            } else {
                showRows = data;
            }

            len = showRows.length;

            for(i=0; i<len; i++) {

                x = [];
                if(attr.chartstyle && attr.chartstyle.indexOf('bar') != -1) {
                    if(originalWidth) {
                        w = originalWidth;
                    } else {
                        w = 0.8;
                    }
                    x.push(1 - w/2. + (i+0.5)*w/(1.0*len));
                    for(j=1; j<showRows[i].length; j++) {
                        x.push(x[j-1] + 1);
                    }
                    attr.width = w/(1.0*len);
                }
                
                if(name && name.length == len)
                    attr.name = name[i];
                else if(attr.withheaders)
                    attr.name = col[i];
                
                if(strokeColor && strokeColor.length == len)
                    attr.strokecolor = strokeColor[i];
                else
                    attr.strokecolor = JXG.hsv2rgb(((i+1)/(1.0*len))*360,0.9,0.6);
                
                if(fillColor && fillColor.length == len)
                    attr.fillcolor = fillColor[i];
                else
                    attr.fillcolor = JXG.hsv2rgb(((i+1)/(1.0*len))*360,0.9,1.0);
                
                if(hStrokeColor && hStrokeColor.length == len)
                    attr.highlightstrokecolor = hStrokeColor[i];
                else
                    attr.highlightstrokecolor = JXG.hsv2rgb(((i+1)/(1.0*len))*360,0.9,1.0);
                
                if(hFillColor && hFillColor.length == len)
                    attr.highlightfillcolor = hFillColor[i];
                else
                    attr.highlightfillcolor = JXG.hsv2rgb(((i+1)/(1.0*len))*360,0.9,0.6);
                
                if(attr.chartstyle && attr.chartstyle.indexOf('bar') != -1) {
                    charts.push(new JXG.Chart(board, [x, showRows[i]], attr));
                } else
                    charts.push(new JXG.Chart(board, [showRows[i]], attr));
            }

            board.unsuspendUpdate();

        }
        return charts;
    } else {
        attr = JXG.copyAttributes(attributes, board.options, 'chart');
        return new JXG.Chart(board, parents, attr);
    }
};

JXG.JSXGraph.registerElement('chart', JXG.createChart);

/**
 * Legend for chart
 * 
 **/
JXG.Legend = function(board, coords, attributes) {
    var attr;

    /* Call the constructor of GeometryElement */
    this.constructor();

    attr = JXG.copyAttributes(attributes, board.options, 'legend');

    this.board = board;
    this.coords = new JXG.Coords(JXG.COORDS_BY_USER, coords, this.board);
    this.myAtts = {};
    this.label_array = attr['labelarray'] || attr.labels;
    this.color_array = attr['colorarray'] || attr.colors;
    this.lines = [];
    this.myAtts['strokewidth'] = attr['strokewidth'] || 5;
    this.myAtts['straightfirst'] = false;
    this.myAtts['straightlast'] = false;
    this.myAtts['withlabel'] = true;
    this.myAtts['fixed'] = true;
    this.style = attr['legendstyle'] || attr.style;

    switch(this.style) {
        case 'vertical':
            this.drawVerticalLegend(board, attr);
            break;
        default:
            throw new Error('JSXGraph: Unknown legend style: ' + this.style);
            break;
    }
};
JXG.Legend.prototype = new JXG.GeometryElement;

JXG.Legend.prototype.drawVerticalLegend = function(board, attributes) {
    var line_length = attributes['linelength'] || 1,
        offy = (attributes['rowheight'] || 20)/this.board.unitY,
        i;

    for(i=0;i<this.label_array.length;i++) {
        this.myAtts['strokecolor'] = this.color_array[i];
        this.myAtts['highlightstrokecolor'] = this.color_array[i];
        this.myAtts['name'] = this.label_array[i];
        this.myAtts['label'] = {offset:[10, 0], strokeColor: this.color_array[i], strokeWidth: this.myAtts.strokewidth};
        
        this.lines[i] = board.create('line', 
                [[this.coords.usrCoords[1],this.coords.usrCoords[2] - i*offy],
                [this.coords.usrCoords[1] + line_length,this.coords.usrCoords[2] - i*offy]],
                this.myAtts
                );

        this.lines[i].getLabelAnchor = function() {
            this.setLabelRelativeCoords(this.visProp.label.offset);
            return new JXG.Coords(JXG.COORDS_BY_USER, [this.point2.X(),this.point2.Y()],this.board);
        }

    }
};

JXG.createLegend = function(board, parents, attributes) {
    //parents are coords of left top point of the legend
    var start_from = [0,0];
    if(JXG.exists(parents))
        if(parents.length == 2) {
            start_from = parents;
        }
    return new JXG.Legend(board, start_from, attributes);
};
JXG.JSXGraph.registerElement('legend', JXG.createLegend);


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview This file contains code for transformations of geometrical objects. 
 * @author graphjs
 * @version 0.1
 *
 * Possible types:
 * - translate
 * - scale
 * - reflect
 * - rotate
 * - shear
 * - generic
 *
 * Rotation matrix:
 * ( 1    0           0   )
 * ( 0    cos(a)   -sin(a))
 * ( 0    sin(a)   cos(a) )
 *
 * Translation matrix:
 * ( 1  0  0)
 * ( a  1  0)
 * ( b  0  1)

 */
JXG.Transformation = function(board,type, params) { 
    this.elementClass = JXG.OBJECT_CLASS_OTHER;                
    this.matrix = [[1,0,0],[0,1,0],[0,0,1]];
    this.board = board;
    this.isNumericMatrix = false;
    this.setMatrix(board,type,params);
};
JXG.Transformation.prototype = {};

JXG.extend(JXG.Transformation.prototype, /** @lends JXG.Transformation.prototype */ {
    update: function(){ return this;},

    /**
     * Set the transformation matrix for different 
     * types of standard transforms
     */
    setMatrix: function(board,type,params) {
        var i;
        
        this.isNumericMatrix = true;
        for (i=0;i<params.length;i++) {
            if (typeof params[i]!='number') {
                this.isNumericMatrix = false;
                break;
            }
        }
        
        if (type=='translate') {
            this.evalParam = JXG.createEvalFunction(board,params,2);
            this.update = function() {
                this.matrix[1][0] = this.evalParam(0);
                this.matrix[2][0] = this.evalParam(1);
            };
        } else if (type=='scale') {
            this.evalParam = JXG.createEvalFunction(board,params,2);
            this.update = function() {
                this.matrix[1][1] = this.evalParam(0); // x
                this.matrix[2][2] = this.evalParam(1); // y
            };
        } else if (type=='reflect') {  // Input: line or two points
            if (params.length<4) { // line or two points
                params[0] = JXG.getReference(board,params[0]);
            }
            if (params.length==2) { // two points
                params[1] = JXG.getReference(board,params[1]);
            }
            if (params.length==4) { // 4 coordinates [px,py,qx,qy]
                this.evalParam = JXG.createEvalFunction(board,params,4);
            }
            this.update = function() {
                var x, y, z, xoff, yoff, d,
                    v, p;
                // Determine homogeneous coordinates of reflections axis
                if (params.length==1) { // line
                    v = params[0].stdform;
                } else if (params.length==2){ // two points
                    v = JXG.Math.crossProduct(params[1].coords.usrCoords, params[0].coords.usrCoords);
                } else if (params.length==4){ // two points coordinates [px,py,qx,qy]
                    v = JXG.Math.crossProduct(
                        [1, this.evalParam(2), this.evalParam(3)],
                        [1, this.evalParam(0), this.evalParam(1)]);
                }
                // Project origin to the line.  This gives a finite point p
                x = v[1];
                y = v[2];
                z = v[0];
                p = [-z*x, -z*y, x*x+y*y];
                d = p[2];
                // Normalize p
                xoff = p[0]/p[2];
                yoff = p[1]/p[2];
                // x, y is the direction of the line
                x = -v[2];
                y =  v[1];
                
                this.matrix[1][1] = (x*x-y*y)/d;
                this.matrix[1][2] = 2*x*y/d;
                this.matrix[2][1] = this.matrix[1][2];
                this.matrix[2][2] = -this.matrix[1][1];
                this.matrix[1][0] = xoff*(1-this.matrix[1][1])-yoff*this.matrix[1][2];
                this.matrix[2][0] = yoff*(1-this.matrix[2][2])-xoff*this.matrix[2][1];
            };
        } else if (type=='rotate') {
            if (params.length==3) { // angle, x, y
                this.evalParam = JXG.createEvalFunction(board,params,3);
            } else if (params.length<=2) { // angle, p or angle
                this.evalParam = JXG.createEvalFunction(board,params,1);
                if (params.length==2) {
                    params[1] = JXG.getReference(board,params[1]);
                } 
            }
            this.update = function() {
                var beta = this.evalParam(0), x, y, co = Math.cos(beta), si = Math.sin(beta);
                this.matrix[1][1] =  co; 
                this.matrix[1][2] = -si;  
                this.matrix[2][1] =  si; 
                this.matrix[2][2] =  co; 
                if (params.length>1) {  // rotate around [x,y] otherwise rotate around [0,0]
                    if (params.length==3) {
                        x = this.evalParam(1);
                        y = this.evalParam(2);
                    } else {
                        x = params[1].X();
                        y = params[1].Y();
                    }
                    this.matrix[1][0] = x*(1-co)+y*si;
                    this.matrix[2][0] = y*(1-co)-x*si;
                }
            };
        } else if (type=='shear') {
            this.evalParam = JXG.createEvalFunction(board,params,1);
            this.update = function() {
                var beta = this.evalParam(0);
                this.matrix[1][1] = Math.tan(beta); 
            };
        } else if (type=='generic') {
            this.evalParam = JXG.createEvalFunction(board,params,9);
            this.update = function() {
                this.matrix[0][0] = this.evalParam(0); 
                this.matrix[0][1] = this.evalParam(1); 
                this.matrix[0][2] = this.evalParam(2); 
                this.matrix[1][0] = this.evalParam(3); 
                this.matrix[1][1] = this.evalParam(4); 
                this.matrix[1][2] = this.evalParam(5); 
                this.matrix[2][0] = this.evalParam(6); 
                this.matrix[2][1] = this.evalParam(7); 
                this.matrix[2][2] = this.evalParam(8); 
            };
        }
    },

    /**
     * Transform a GeometryElement:
     * First, update the matrix
     * Second, do the matrix-vector-multiplication
     *
     * @param {JXG.GeometryElement} element, which is transformed
     */
    apply: function(p){
        this.update();
        if (arguments[1] != null) {
            return JXG.Math.matVecMult(this.matrix,p.initialCoords.usrCoords);
        } else {
            return JXG.Math.matVecMult(this.matrix,p.coords.usrCoords);
        }
    },

    /**
     * Apply a transformation once to a GeometryElement.
     * If it is a free point, then it can be dragged around later
     * and will overwrite the transformed coordinates.
     * @param {JXG.Point|Array} p
     */
    applyOnce: function(p){
        var c, len, i;
        
        if (!JXG.isArray(p)) {
            p = [p];
        }
        
        len = p.length;
        for (i = 0; i < len; i++) {
            this.update();
            c = JXG.Math.matVecMult(this.matrix, p[i].coords.usrCoords);
            p[i].coords.setCoordinates(JXG.COORDS_BY_USER, c);
        }
        
    },

    /**
     * Bind a transformation to a GeometryElement
     */
    bindTo: function(p){
        var i, len;
        if (JXG.isArray(p)) {   
            len = p.length;
            for (i=0; i<len; i++) {
                p[i].transformations.push(this);
            }
        } else {
            p.transformations.push(this);
        }
    },

    setProperty: function(term) {
    },

    /**
     * Multiplication of a transformation t from the right.
     * this = t join this
     */
    melt: function(t){
        var res = [], i, len, len0, k, s, j;
        
        len = t.matrix.length;
        len0 = this.matrix[0].length;
        
        for (i=0;i<len;i++) {
            res[i] = [];
        }
        this.update();
        t.update();
        for (i=0;i<len;i++) {
            for (j=0;j<len0;j++) {
                s = 0;
                for (k=0;k<len;k++) {
                    s += t.matrix[i][k]*this.matrix[k][j];
                }
                res[i][j] = s;
            }
        }
        this.update = function() {
            var len = this.matrix.length,
                len0 = this.matrix[0].length;
            for (i=0;i<len;i++) {
                for (j=0;j<len0;j++) {
                    this.matrix[i][j] = res[i][j];
                }
            }
        };
        return this;
    }
});

JXG.createTransform = function(board, parents, attributes) {
    return new JXG.Transformation(board, attributes['type'], parents);
};

JXG.JSXGraph.registerElement('transform', JXG.createTransform);


 /*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @fileoverview The JSXGraph object Turtle is defined. It acts like
 * "turtle graphics".
 * @author A.W.
 */

/**
 * Constructs a new Turtle object.
 * @class This is the Turtle class. 
 * It is derived from {@link JXG.GeometryElement}.
 * It stores all properties required
 * to move a turtle.
 * @constructor
 * @param {String} JXG.board The board the new turtle is drawn on.
 * @param {Array}  [x,y,angle] Start position and start direction of the turtle. Possible values are
 * [x,y,angle]
 * [[x,y],angle]
 * [x,y]
 * [[x,y]]
 * @param {Object} attributes Attributes to change the visual properties of the turtle object
 * All angles are in degrees.
  */
JXG.Turtle = function (board, parents, attributes) {
    this.constructor(board, attributes, JXG.OBJECT_TYPE_TURTLE, JXG.OBJECT_CLASS_OTHER);

    var x,y,dir;
    this.turtleIsHidden = false;
    this.board = board;
    this.visProp.curveType = 'plot';

    // Save visProp in this._attributes.
    // this._attributes is overwritten by setPenSize, setPenColor...
    // Setting the color or size affects the turtle from the time of
    // calling the method,
    // whereas Turtle.setProperty affects all turtle curves.
    this._attributes = JXG.copyAttributes(this.visProp, board.options, 'turtle');
    delete(this._attributes['id']);
    
    x = 0;
    y = 0;
    dir = 90;
    if (parents.length!=0) {
        if (parents.length==3) {   // [x,y,dir]
            // Only numbers are accepted at the moment
            x = parents[0];
            y = parents[1];
            dir = parents[2];
        } else if (parents.length==2) {
            if (JXG.isArray(parents[0])) {  // [[x,y],dir]
                x = parents[0][0];
                y = parents[0][1];
                dir = parents[1];
            } else {  // [x,y]
                x = parents[0];
                y = parents[1];
            }
        } else { // [[x,y]]
            x = parents[0][0];
            y = parents[0][1];
        }
    }
    
    this.init(x,y,dir);
    return this;
};
JXG.Turtle.prototype = new JXG.GeometryElement;

JXG.extend(JXG.Turtle.prototype, /** @lends JXG.Turtle.prototype */ {
    /**
    * Initialize a new turtle or reinitialize  a turtle after {@link #clearscreen}.
    * @private
    */
    init: function(x,y,dir) {
        this.arrowLen = 20.0/Math.sqrt(this.board.unitX*this.board.unitX+this.board.unitY*this.board.unitY);

        this.pos = [x,y];
        this.isPenDown = true;
        this.dir = 90;
        this.stack = [];
        this.objects = [];
        this.curve = this.board.create('curve',[[this.pos[0]],[this.pos[1]]], this._attributes);
        this.objects.push(this.curve);

        this.turtle = this.board.create('point',this.pos,{fixed:true, name:' ', visible:false, withLabel:false});
        this.objects.push(this.turtle);
        
        this.turtle2 = this.board.create('point',[this.pos[0],this.pos[1]+this.arrowLen],
                {fixed:true, name:' ', visible:false, withLabel:false});
        this.objects.push(this.turtle2);
        
		this.visProp.arrow['lastArrow'] = true;
		this.visProp.arrow['straightFirst'] = false;
		this.visProp.arrow['straightLast'] = false;
        this.arrow = this.board.create('line', [this.turtle,this.turtle2], this.visProp.arrow);
        this.objects.push(this.arrow);

        this.right(90-dir);
        this.board.update();
    },

    /**
    * Move the turtle forward.
    * @param {float} length of forward move in user coordinates
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    forward: function(len) {
        if (len === 0) {
            return this;
        }

        var dx = len*Math.cos(this.dir*Math.PI/180.0),
            dy = len*Math.sin(this.dir*Math.PI/180.0);
        
        if (!this.turtleIsHidden) {
            var t = this.board.create('transform', [dx,dy], {type:'translate'});
            t.applyOnce(this.turtle);
            t.applyOnce(this.turtle2);
        }
        if (this.isPenDown) if (this.curve.dataX.length>=8192) { // IE workaround
            this.curve = this.board.create('curve',
                   [[this.pos[0]],[this.pos[1]]], this._attributes);
            this.objects.push(this.curve);
        }
        this.pos[0] += dx;
        this.pos[1] += dy;
        if (this.isPenDown) {
            this.curve.dataX.push(this.pos[0]);
            this.curve.dataY.push(this.pos[1]);
        }

        this.board.update();
        return this;
    },
     
    /**
    * Move the turtle backwards.
    * @param {float} length of backwards move in user coordinates
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    back: function(len) {
        return this.forward(-len);
    },
     
    /**
    * Rotate the turtle direction to the right
    * @param {float} angle of the rotation in degrees
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    right: function(angle) {
        this.dir -= angle;
        this.dir %= 360.0;
        if (!this.turtleIsHidden) {
            var t = this.board.create('transform', [-angle*Math.PI/180.0,this.turtle], {type:'rotate'});
            t.applyOnce(this.turtle2);
        }
        this.board.update();
        return this;
    },
     
    /**
    * Rotate the turtle direction to the right.
    * @param {float} angle of the rotation in degrees
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    left: function(angle) {
        return this.right(-angle);
    },

    /**
    * Pen up, stops visible drawing
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    penUp: function() {
        this.isPenDown = false;
        return this;
    },

    /**
    * Pen down, continues visible drawing
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    penDown: function() {
        this.isPenDown = true;
        this.curve = this.board.create('curve',[[this.pos[0]],[this.pos[1]]], this._attributes);
        this.objects.push(this.curve);
		
        return this;
    },

    /**
    *  Removes the turtle curve from the board. The turtle stays in its position.
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    clean: function() {
        for(var i=0;i<this.objects.length;i++) {
            var el = this.objects[i];
            if (el.type==JXG.OBJECT_TYPE_CURVE) {
                this.board.removeObject(el);
                this.objects.splice(i,1);
            }
        }
        this.curve = this.board.create('curve',
                  [[this.pos[0]],[this.pos[1]]], this._attributes);
        this.objects.push(this.curve);
        this.board.update();
        return this;
    },

    /**
    *  Removes the turtle completely and resets it to its initial position and direction.
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    clearScreen: function() {
        var i, el, len = this.objects.length;
        for(i=0; i<len; i++) {
            el = this.objects[i];
            this.board.removeObject(el);
        }
        this.init(0,0, 90);
        return this;
    },

    /**
    *  Moves the turtle without drawing to a new position
    * @param {float} x new x- coordinate 
    * @param {float} y new y- coordinate 
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    setPos: function(x,y) {
        if (JXG.isArray(x)) {
            this.pos = x;
        } else {
            this.pos = [x,y];
        }
        if (!this.turtleIsHidden) {
            this.turtle.setPositionDirectly(JXG.COORDS_BY_USER, [x, y]);
            this.turtle2.setPositionDirectly(JXG.COORDS_BY_USER, [x, y + this.arrowLen]);
            var t = this.board.create('transform', 
                    [-(this.dir-90)*Math.PI/180.0,this.turtle], {type:'rotate'});
            t.applyOnce(this.turtle2);
        }
        this.curve = this.board.create('curve',[[this.pos[0]],[this.pos[1]]], this._attributes);
        this.objects.push(this.curve);
        this.board.update();
        return this;
    },

    /**
    *  Sets the pen size. Equivalent to setProperty({strokeWidth:size})
    * but affects only the future turtle.
    * @param {float} size
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
   setPenSize: function(size) { 
        //this.visProp.strokewidth = size; 
        this.curve = this.board.create('curve',[[this.pos[0]],[this.pos[1]]], this.copyAttr('strokeWidth', size));
        this.objects.push(this.curve);
        return this;
    },

    /**
    *  Sets the pen color. Equivalent to setProperty({strokeColor:color})
    * but affects only the future turtle.
    * @param {string} color
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    setPenColor: function(colStr) { 
        //this.visProp.strokecolor = colStr; 
        this.curve = this.board.create('curve',[[this.pos[0]],[this.pos[1]]], this.copyAttr('strokeColor', colStr));
        this.objects.push(this.curve);
        return this;
    },

    /**
    *  Sets the highlight pen color. Equivalent to setProperty({highlightStrokeColor:color})
    * but affects only the future turtle.
    * @param {string} color
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    setHighlightPenColor: function(colStr) { 
        //this.visProp.highlightstrokecolor = colStr; 
        this.curve = this.board.create('curve',[[this.pos[0]],[this.pos[1]]], this.copyAttr('highlightStrokeColor', colStr));
        this.objects.push(this.curve);
        return this;
    },

    /**
    * Sets properties of the turtle, see also {@link JXG.GeometryElement#setProperty}.
    * Sets the property for all curves of the turtle in the past and in the future.
    * @param {Object} key:value pairs
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    setProperty: function(attributes) {
        var i, el, len = this.objects.length, tmp;
        for (i=0; i<len; i++) {
            el = this.objects[i];
            if (el.type==JXG.OBJECT_TYPE_CURVE) {
                el.setProperty(attributes);
            }
        }
        // Set visProp of turtle
        tmp = this.visProp['id'];
        this.visProp = JXG.deepCopy(this.curve.visProp);
        this.visProp['id'] = tmp;
        this._attributes = JXG.deepCopy(this.visProp);
        delete(this._attributes['id']);
        return this;
    },
    
    /**
    * Set a future attribute of the turtle.
    * @private
    * @param {String} key
    * @param {Object} value (number, string)
    * @type {Object}
    * @return pointer to an attributes object
    */
    copyAttr: function(key, val) {
        this._attributes[key.toLowerCase()] = val;
        return this._attributes;
    },

    /**
    * Sets the visibility of the turtle head to true,
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    showTurtle: function() { 
        this.turtleIsHidden = false; 
        this.arrow.setProperty({visible:true});
        this.visProp.arrow['visible'] = false;
        this.setPos(this.pos[0],this.pos[1]);
        this.board.update();
        return this;
    },

    /**
    * Sets the visibility of the turtle head to false,
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    hideTurtle: function() { 
        this.turtleIsHidden = true;
        this.arrow.setProperty({visible:false});
        this.visProp.arrow['visible'] = false;
        //this.setPos(this.pos[0],this.pos[1]);
        this.board.update();
        return this;
    },

    /**
    * Moves the turtle to position [0,0].
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    home: function() { 
        this.pos = [0,0];
        this.setPos(this.pos[0],this.pos[1]);
        return this;
    },

    /**
    *  Pushes the position of the turtle on the stack.
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    pushTurtle: function() { 
        this.stack.push([this.pos[0],this.pos[1],this.dir]);
        return this;
    },

    /**
    *  Gets the last position of the turtle on the stack, sets the turtle to this position and removes this 
    * position from the stack.
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    popTurtle: function() { 
        var status = this.stack.pop();
        this.pos[0] = status[0];
        this.pos[1] = status[1];
        this.dir = status[2];
        this.setPos(this.pos[0],this.pos[1]);
        return this;
    },

    /**
    * Rotates the turtle into a new direction.
    * There are two possibilities:
    * @param {float} angle New direction to look to
    * or
    * @param {float} x New x coordinate to look to
    * @param {float} y New y coordinate to look to
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    lookTo: function(target) { 
        if (JXG.isArray(target)) {
            var ax = this.pos[0];
            var ay = this.pos[1];
            var bx = target[0];
            var by = target[1];
            var beta; 
            // Rotate by the slope of the line [this.pos, target]
            /*
            var sgn = (bx-ax>0)?1:-1;
            if (Math.abs(bx-ax)>0.0000001) {
                beta = Math.atan2(by-ay,bx-ax)+((sgn<0)?Math.PI:0);  
            } else {
                beta = ((by-ay>0)?0.5:-0.5)*Math.PI;
            }
            */
            beta = Math.atan2(by-ay,bx-ax);
            this.right(this.dir-(beta*180/Math.PI));
        } else if (JXG.isNumber(target)) {
            this.right(this.dir-(target));
        }
        return this;
    },

    /**
    * Moves the turtle to a given coordinate pair.
    * The direction is not changed.
    * @param {float} x New x coordinate to look to
    * @param {float} y New y coordinate to look to
    * @type {JXG.Turtle}
    * @return pointer to the turtle object
    */
    moveTo: function(target) { 
        if (JXG.isArray(target)) {
            var dx = target[0]-this.pos[0];
            var dy = target[1]-this.pos[1];
            if (!this.turtleIsHidden) {
                var t = this.board.create('transform', [dx,dy], {type:'translate'});
                t.applyOnce(this.turtle);
                t.applyOnce(this.turtle2);
            }
            if (this.isPenDown) if (this.curve.dataX.length>=8192) { // IE workaround
                this.curve = this.board.create('curve',
                   [[this.pos[0]],[this.pos[1]]], this._attributes);
                this.objects.push(this.curve);
            }
            this.pos[0] = target[0];
            this.pos[1] = target[1];
            if (this.isPenDown) {
                this.curve.dataX.push(this.pos[0]);
                this.curve.dataY.push(this.pos[1]);
            }
            this.board.update();
        }
        return this;
    },

    /**
      * Alias for {@link #forward}
      */
    fd: function(len) { return this.forward(len); },
    /**
      * Alias for {@link #back}
      */
    bk: function(len) { return this.back(len); },
    /**
      * Alias for {@link #left}
      */
    lt: function(angle) { return this.left(angle); },
    /**
      * Alias for {@link #right}
      */
    rt: function(angle) { return this.right(angle); },
    /**
      * Alias for {@link #penUp}
      */
    pu: function() { return this.penUp(); },
    /**
      * Alias for {@link #penDown}
      */
    pd: function() { return this.penDown(); },
    /**
      * Alias for {@link #hideTurtle}
      */
    ht: function() { return this.hideTurtle(); },
    /**
      * Alias for {@link #showTurtle}
      */
    st: function() { return this.showTurtle(); },
    /**
      * Alias for {@link #clearScreen}
      */
    cs: function() { return this.clearScreen(); },
    /**
      * Alias for {@link #pushTurtle}
      */
    push: function() { return this.pushTurtle(); },
    /**
      * Alias for {@link #popTurtle}
      */
    pop: function() { return this.popTurtle(); },

    /**
     * the "co"-coordinate of the turtle curve at position t is returned.
     * @param {float} t parameter 
     * @param {string} coordinate. Either 'X' or 'Y'.
     * @return {float} x-coordinate of the turtle position or x-coordinate of turtle at position t
     */
    evalAt: function(/** float */ t, /** string */ co) /** float */ { 
        var i, j, el, tc, len = this.objects.length;
        for (i=0, j=0; i<len; i++) {
            el = this.objects[i]; 
            if (el.elementClass == JXG.OBJECT_CLASS_CURVE) {
                if (j<=t && t<j+el.numberPoints) {
                    tc = (t-j);
                    return el[co](tc);
                }
                j += el.numberPoints;
            }
        }
        return this[co]();
    },

    /**
     * if t is not supplied the x-coordinate of the turtle is returned. Otherwise
     * the x-coordinate of the turtle curve at position t is returned.
     * @param {float} t parameter 
     * @return {float} x-coordinate of the turtle position or x-coordinate of turtle at position t
     */
    X: function(/** float */ t) /** float */ { 
        if (typeof t == 'undefined' ) {
            return this.pos[0]; //this.turtle.X();
        } else {
            return this.evalAt(t, 'X');
        }
    },

    /**
     * if t is not supplied the y-coordinate of the turtle is returned. Otherwise
     * the y-coordinate of the turtle curve at position t is returned.
     * @param {float} t parameter 
     * @return {float} x-coordinate of the turtle position or x-coordinate of turtle at position t
     */
    Y: function(/** float */ t) /** float */ { 
        if (typeof t == 'undefined' ) {
            return this.pos[1]; //this.turtle.Y();
        } else {
            return this.evalAt(t, 'Y');
        }
    },

    /**
    * @return z-coordinate of the turtle position
    * @type {float}
    */
    Z: function(/** float */ t) /** float */ { 
        return 1.0; 
    },

    /**
     * Gives the lower bound of the parameter if the the turtle is treated as parametric curve.
     */
    minX: function () {
        return 0;
    },

    /**
     * Gives the upper bound of the parameter if the the turtle is treated as parametric curve.
     * May be overwritten in @see generateTerm.
     */
    maxX: function () {
        var np = 0, i, len = this.objects.length, el;
        for (i=0; i <len; i++) {
            el = this.objects[i];
            if (el.elementClass == JXG.OBJECT_CLASS_CURVE) {
                np += this.objects[i].numberPoints; 
            }
        }
        return np;
    },

    /**
     * Checks whether (x,y) is near the curve.
     * @param {int} x Coordinate in x direction, screen coordinates.
     * @param {int} y Coordinate in y direction, screen coordinates.
     * @param {y} Find closest point on the curve to (x,y)
     * @return {bool} True if (x,y) is near the curve, False otherwise.
     */
    hasPoint: function (x,y) {
        var i, el;
        for(i=0;i<this.objects.length;i++) {  // run through all curves of this turtle
            el = this.objects[i];
            if (el.type==JXG.OBJECT_TYPE_CURVE) {
                if (el.hasPoint(x,y)) {
                    return true;              // So what??? All other curves have to be notified now (for highlighting)
                                              // This has to be done, yet.
                }
            }
        }
        return false;
    }
});

/**
 * Creates a new turtle
 * @param {JXG.Board} board The board the turtle is put on.
 * @param {Array} parents 
 * @param {Object} attributs Object containing properties for the element such as stroke-color and visibility. See {@link JXG.GeometryElement#setProperty}
 * @type JXG.Turtle
 * @return Reference to the created turtle object.
 */
JXG.createTurtle = function(board, parents, attributes) {
	var attr;
    parents = parents || [];

    attr = JXG.copyAttributes(attributes, board.options, 'turtle');
    return new JXG.Turtle(board, parents, attr);
};

JXG.JSXGraph.registerElement('turtle', JXG.createTurtle);


/**
 * Functions for color conversions. Based on a class to parse color values by Stoyan Stefanov <sstoo@gmail.com>
 * @see http://www.phpied.com/rgb-color-parser-in-javascript/
 */

/**
 * Converts a valid HTML/CSS color string into a rgb value array. This is the base
 * function for the following wrapper functions which only adjust the output to
 * different flavors like an object, string or hex values.
 * @parameter {string} color_string A valid HTML or CSS styled color value, e.g. #12ab21, #abc, black, or rgb(12, 132, 233) <strong>or</string>
 * @parameter {array} color_array Array containing three color values either from 0.0 to 1.0 or from 0 to 255. They will be interpreted as red, green, and blue values <strong>OR</strong>
 * @parameter {number} r,g,b Three color values r, g, and b like those in the array variant.
 * @returns {Array} RGB color values as an array [r, g, b] which component's are between 0 and 255.
 */
JXG.rgbParser = function() {
    var color_string,
        testFloat = false,
        i,
        r, g, b;

    if(arguments.length === 0) {
        return [];
    }

    if(arguments.length >= 3) {
        arguments[0] = [arguments[0], arguments[1], arguments[2]];
        arguments.length = 1;
    }

    color_string = arguments[0];
    if(JXG.isArray(color_string)) {
        for(i = 0; i < 3; i++) {
            testFloat |= /\./.test(arguments[0][i].toString());
        }

        for(i = 0; i < 3; i++) {
            testFloat &= (arguments[0][i] >= 0.0) & (arguments[0][i] <= 1.0);
        }

        if(testFloat)
            return [Math.ceil(arguments[0][0] * 255), Math.ceil(arguments[0][1] * 255), Math.ceil(arguments[0][2] * 255)];
        else {
            arguments[0].length = 3;
            return arguments[0];
        }
    } else if(typeof arguments[0] === 'string') {
        color_string = arguments[0];
    }

    // strip any leading #
    if (color_string.charAt(0) == '#') { // remove # if any
        color_string = color_string.substr(1,6);
    }

    color_string = color_string.replace(/ /g,'').toLowerCase();

    // before getting into regexps, try simple matches
    // and overwrite the input
    var simple_colors = {
        aliceblue: 'f0f8ff',
        antiquewhite: 'faebd7',
        aqua: '00ffff',
        aquamarine: '7fffd4',
        azure: 'f0ffff',
        beige: 'f5f5dc',
        bisque: 'ffe4c4',
        black: '000000',
        blanchedalmond: 'ffebcd',
        blue: '0000ff',
        blueviolet: '8a2be2',
        brown: 'a52a2a',
        burlywood: 'deb887',
        cadetblue: '5f9ea0',
        chartreuse: '7fff00',
        chocolate: 'd2691e',
        coral: 'ff7f50',
        cornflowerblue: '6495ed',
        cornsilk: 'fff8dc',
        crimson: 'dc143c',
        cyan: '00ffff',
        darkblue: '00008b',
        darkcyan: '008b8b',
        darkgoldenrod: 'b8860b',
        darkgray: 'a9a9a9',
        darkgreen: '006400',
        darkkhaki: 'bdb76b',
        darkmagenta: '8b008b',
        darkolivegreen: '556b2f',
        darkorange: 'ff8c00',
        darkorchid: '9932cc',
        darkred: '8b0000',
        darksalmon: 'e9967a',
        darkseagreen: '8fbc8f',
        darkslateblue: '483d8b',
        darkslategray: '2f4f4f',
        darkturquoise: '00ced1',
        darkviolet: '9400d3',
        deeppink: 'ff1493',
        deepskyblue: '00bfff',
        dimgray: '696969',
        dodgerblue: '1e90ff',
        feldspar: 'd19275',
        firebrick: 'b22222',
        floralwhite: 'fffaf0',
        forestgreen: '228b22',
        fuchsia: 'ff00ff',
        gainsboro: 'dcdcdc',
        ghostwhite: 'f8f8ff',
        gold: 'ffd700',
        goldenrod: 'daa520',
        gray: '808080',
        green: '008000',
        greenyellow: 'adff2f',
        honeydew: 'f0fff0',
        hotpink: 'ff69b4',
        indianred : 'cd5c5c',
        indigo : '4b0082',
        ivory: 'fffff0',
        khaki: 'f0e68c',
        lavender: 'e6e6fa',
        lavenderblush: 'fff0f5',
        lawngreen: '7cfc00',
        lemonchiffon: 'fffacd',
        lightblue: 'add8e6',
        lightcoral: 'f08080',
        lightcyan: 'e0ffff',
        lightgoldenrodyellow: 'fafad2',
        lightgrey: 'd3d3d3',
        lightgreen: '90ee90',
        lightpink: 'ffb6c1',
        lightsalmon: 'ffa07a',
        lightseagreen: '20b2aa',
        lightskyblue: '87cefa',
        lightslateblue: '8470ff',
        lightslategray: '778899',
        lightsteelblue: 'b0c4de',
        lightyellow: 'ffffe0',
        lime: '00ff00',
        limegreen: '32cd32',
        linen: 'faf0e6',
        magenta: 'ff00ff',
        maroon: '800000',
        mediumaquamarine: '66cdaa',
        mediumblue: '0000cd',
        mediumorchid: 'ba55d3',
        mediumpurple: '9370d8',
        mediumseagreen: '3cb371',
        mediumslateblue: '7b68ee',
        mediumspringgreen: '00fa9a',
        mediumturquoise: '48d1cc',
        mediumvioletred: 'c71585',
        midnightblue: '191970',
        mintcream: 'f5fffa',
        mistyrose: 'ffe4e1',
        moccasin: 'ffe4b5',
        navajowhite: 'ffdead',
        navy: '000080',
        oldlace: 'fdf5e6',
        olive: '808000',
        olivedrab: '6b8e23',
        orange: 'ffa500',
        orangered: 'ff4500',
        orchid: 'da70d6',
        palegoldenrod: 'eee8aa',
        palegreen: '98fb98',
        paleturquoise: 'afeeee',
        palevioletred: 'd87093',
        papayawhip: 'ffefd5',
        peachpuff: 'ffdab9',
        peru: 'cd853f',
        pink: 'ffc0cb',
        plum: 'dda0dd',
        powderblue: 'b0e0e6',
        purple: '800080',
        red: 'ff0000',
        rosybrown: 'bc8f8f',
        royalblue: '4169e1',
        saddlebrown: '8b4513',
        salmon: 'fa8072',
        sandybrown: 'f4a460',
        seagreen: '2e8b57',
        seashell: 'fff5ee',
        sienna: 'a0522d',
        silver: 'c0c0c0',
        skyblue: '87ceeb',
        slateblue: '6a5acd',
        slategray: '708090',
        snow: 'fffafa',
        springgreen: '00ff7f',
        steelblue: '4682b4',
        tan: 'd2b48c',
        teal: '008080',
        thistle: 'd8bfd8',
        tomato: 'ff6347',
        turquoise: '40e0d0',
        violet: 'ee82ee',
        violetred: 'd02090',
        wheat: 'f5deb3',
        white: 'ffffff',
        whitesmoke: 'f5f5f5',
        yellow: 'ffff00',
        yellowgreen: '9acd32'
    };
    color_string = simple_colors[color_string] || color_string;
    // end of simple type-in colors

    // array of color definition objects
    var color_defs = [
        {
            re: /^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d\.]{1,3})\s*\)\s*$/,
            example: ['rgba(123, 234, 45, 0.5)', 'rgba(255,234,245,1.0)'],
            process: function (bits){
                return [
                    parseInt(bits[1]),
                    parseInt(bits[2]),
                    parseInt(bits[3])
                ];
            }
        },
        {
            re: /^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$/,
            example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
            process: function (bits){
                return [
                    parseInt(bits[1]),
                    parseInt(bits[2]),
                    parseInt(bits[3])
                ];
            }
        },
        {
            re: /^(\w{2})(\w{2})(\w{2})$/,
            example: ['#00ff00', '336699'],
            process: function (bits){
                return [
                    parseInt(bits[1], 16),
                    parseInt(bits[2], 16),
                    parseInt(bits[3], 16)
                ];
            }
        },
        {
            re: /^(\w{1})(\w{1})(\w{1})$/,
            example: ['#fb0', 'f0f'],
            process: function (bits){
                return [
                    parseInt(bits[1] + bits[1], 16),
                    parseInt(bits[2] + bits[2], 16),
                    parseInt(bits[3] + bits[3], 16)
                ];
            }
        }
    ];

    // search through the definitions to find a match
    for (i = 0; i < color_defs.length; i++) {
        var re = color_defs[i].re,
            processor = color_defs[i].process,
            bits = re.exec(color_string),
            channels;
        if (bits) {
            channels = processor(bits);
            r = channels[0];
            g = channels[1];
            b = channels[2];
        }

    }

    if (isNaN(r) || isNaN(g) || isNaN(b)) {
        return [];
    }

    // validate/cleanup values
    r = (r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r);
    g = (g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g);
    b = (b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b);

    return [r, g, b];
};

/**
 * Returns output of JXG.rgbParser as a CSS styled rgb() string.
 */
JXG.rgb2css = function () {
    var r, g, b;
    r = JXG.rgbParser.apply(JXG.rgbParser, arguments);
    g = r[1];
    b = r[2];
    r = r[0];
    return 'rgb(' + r + ', ' + g + ', ' + b + ')';
};

/**
 * Returns array returned by JXG.rgbParser as a HTML rgb string.
 */
JXG.rgb2hex = function () {
    var r, g, b;
    r = JXG.rgbParser.apply(JXG.rgbParser, arguments);
    g = r[1];
    b = r[2];
    r = r[0];
    r = r.toString(16);
    g = g.toString(16);
    b = b.toString(16);
    if (r.length == 1) r = '0' + r;
    if (g.length == 1) g = '0' + g;
    if (b.length == 1) b = '0' + b;
    return '#' + r + g + b;
};

JXG.hex2rgb = function (hex) {
    var r, g, b;
    if (hex.charAt(0) == '#')
        hex = hex.slice(1);

    r = parseInt(hex.substr(0, 2), 16);
    g = parseInt(hex.substr(2, 2), 16);
    b = parseInt(hex.substr(4, 2), 16);

    return 'rgb(' + r + ', ' + g + ', ' + b + ')';
};

/**
* Converts HSV color to RGB color.
* Based on C Code in "Computer Graphics -- Principles and Practice,"
* Foley et al, 1996, p. 593.
* See also http://www.efg2.com/Lab/Graphics/Colors/HSV.htm  
* @param {float} H value between 0 and 360
* @param {float} S value between 0.0 (shade of gray) to 1.0 (pure color)
* @param {float} V value between 0.0 (black) to 1.0 (white)
* @return {string} RGB color string
*/
JXG.hsv2rgb = function(H,S,V) {
    var R,G,B, f,i,hTemp, p,q,t;
    H = ((H%360.0)+360.0)%360;
    if (S==0) {
        if (isNaN(H) || H < JXG.Math.eps) {
            R = V;
            G = V;
            B = V;
        } else {
            return '#ffffff';
        }
    } else {
        if (H>=360) {
            hTemp = 0.0;
        } else {
            hTemp = H;
        }
        hTemp = hTemp / 60;     // h is now IN [0,6)
        i = Math.floor(hTemp);        // largest integer <= h
        f = hTemp - i;                  // fractional part of h
        p = V * (1.0 - S);
        q = V * (1.0 - (S * f));
        t = V * (1.0 - (S * (1.0 - f)));
        switch (i) {
            case 0: R = V; G = t;  B = p; break;
            case 1: R = q; G = V;  B = p; break;
            case 2: R = p; G = V;  B = t; break;
            case 3: R = p; G = q;  B = V; break;
            case 4: R = t; G = p;  B = V; break;
            case 5: R = V; G = p;  B = q; break;
        }
    }
    R = Math.round(R*255).toString(16); R = (R.length==2)?R:((R.length==1)?'0'+R:'00');
    G = Math.round(G*255).toString(16); G = (G.length==2)?G:((G.length==1)?'0'+G:'00');
    B = Math.round(B*255).toString(16); B = (B.length==2)?B:((B.length==1)?'0'+B:'00');
    return ['#',R,G,B].join(''); 
};

/**
 * Converts r, g, b color to h, s, v.
 * See http://zach.in.tu-clausthal.de/teaching/cg1_0708/folien/13_color_3_4up.pdf for more information.
 * @param {number} r Amount of red in color. Number between 0 and 255.
 * @param {number} g Amount of green. Number between 0 and 255.
 * @param {number} b Amount of blue. Number between 0 and 255.
 * @type Object
 * @return Hashmap containing h,s, and v field.
 */
JXG.rgb2hsv = function() {
    var r, g, b, fr, fg, fb, fmax, fmin, h, s, v, max, min, stx;
    r = JXG.rgbParser.apply(JXG.rgbParser, arguments);
    g = r[1];
    b = r[2];
    r = r[0];
    stx = JXG.Math.Statistics;
    fr = r/255.;
    fg = g/255.;
    fb = b/255.;
    max = stx.max([r, g, b]);
    min = stx.min([r, g, b]);
    fmax = max/255.;
    fmin = min/255.;

    v = fmax;

    s = 0.;
    if(v>0) {
        s = (v-fmin)/(v*1.);
    }

    h = 1./(fmax-fmin);
    if(s > 0) {
        if(max==r)
            h = (fg-fb)*h;
        else if(max==g)
            h = 2 + (fb-fr)*h;
        else
            h = 4 + (fr-fg)*h;
    }

    h *= 60;
    if(h < 0)
        h += 360;

    if(max==min)
        h = 0.;

    return [h, s, v];
};


/**
 * Convert RGB color information to LMS color space.
 * @param {number} r Amount of red in color. Number between 0 and 255.
 * @param {number} g Amount of green. Number between 0 and 255.
 * @param {number} b Amount of blue. Number between 0 and 255.
 * @type Object
 * @return Hashmap containing the L, M, S cone values.
 */
JXG.rgb2LMS = function() {
    var r, g, b, l, m, s, ret,
        // constants
        matrix = [[0.05059983, 0.08585369, 0.00952420], [0.01893033, 0.08925308, 0.01370054], [0.00292202, 0.00975732, 0.07145979]];

    r = JXG.rgbParser.apply(JXG.rgbParser, arguments);
    g = r[1];
    b = r[2];
    r = r[0];

    // de-gamma
    // Maybe this can be made faster by using a cache
    r = Math.pow(r, 0.476190476);
    g = Math.pow(g, 0.476190476);
    b = Math.pow(b, 0.476190476);

    l = r * matrix[0][0] + g * matrix[0][1] + b * matrix[0][2];
    m = r * matrix[1][0] + g * matrix[1][1] + b * matrix[1][2];
    s = r * matrix[2][0] + g * matrix[2][1] + b * matrix[2][2];

    ret = [l, m, s];
    ret.l = l;
    ret.m = m;
    ret.s = s;

    return ret;
};
/**
 * Convert color information from LMS to RGB color space.
 * @param {number} l Amount of l value.
 * @param {number} m Amount of m value.
 * @param {number} s Amount of s value.
 * @type Object
 * @return Hashmap containing the r, g, b values.
 */
JXG.LMS2rgb = function(l, m, s) {
    var r, g, b, ret,
        // constants
        matrix = [[30.830854, -29.832659, 1.610474], [-6.481468, 17.715578, -2.532642], [-0.375690, -1.199062, 14.273846]];

    // transform back to rgb
    r = l * matrix[0][0] + m * matrix[0][1] + s * matrix[0][2];
    g = l * matrix[1][0] + m * matrix[1][1] + s * matrix[1][2];
    b = l * matrix[2][0] + m * matrix[2][1] + s * matrix[2][2];

    // re-gamma, inspired by GIMP modules/display-filter-color-blind.c:
    // Copyright (C) 2002-2003 Michael Natterer <mitch@gimp.org>,
    //                         Sven Neumann <sven@gimp.org>,
    //                         Robert Dougherty <bob@vischeck.com> and
    //                         Alex Wade <alex@vischeck.com>
    // This code is an implementation of an algorithm described by Hans Brettel,
    // Francoise Vienot and John Mollon in the Journal of the Optical Society of
    // America V14(10), pg 2647. (See http://vischeck.com/ for more info.)
    var lut_lookup = function (value) {
        var offset = 127, step = 64;

        while (step > 0) {
            if (Math.pow(offset, 0.476190476) > value) {
                offset -= step;
            } else {
                if (Math.pow(offset+1, 0.476190476) > value)
                    return offset;

                offset += step;
            }

            step /= 2;
        }

        /*  the algorithm above can't reach 255  */
        if (offset == 254 && 13.994955247 < value)
            return 255;

        return offset;
    };


    r = lut_lookup(r);
    g = lut_lookup(g);
    b = lut_lookup(b);

    ret = [r, g, b];
    ret.r = r;
    ret.g = g;
    ret.b = b;

    return ret;
};

/**
 * Splits a RGBA color value like #112233AA into it's RGB and opacity parts.
 * @param {String} rgba A RGBA color value
 * @returns {Array} An array containing the rgb color value in the first and the opacity in the second field.
 */
JXG.rgba2rgbo = function (rgba) {
    var opacity;

    if (rgba.length == 9 && rgba.charAt(0) == '#') {
        opacity = parseInt(rgba.substr(7, 2).toUpperCase(), 16) / 255;
        rgba = rgba.substr(0, 7);
    } else {
        opacity = 1;
    }

    return [rgba, opacity];
};

/**
 * Generates a RGBA color value like #112233AA from it's RGB and opacity parts.
 * @param {String} rgb A RGB color value.
 * @param {Float} o The desired opacity >=0, <=1.
 * @returns {String} The RGBA color value.
 */
JXG.rgbo2rgba = function (rgb, o) {
    var rgba;

    if (rgb == 'none')
        return rgb;

    rgba = Math.round(o*255).toString(16);
    if (rgba.length == 1)
        rgba = "0" + rgba;

    return rgb + rgba;
};

/**
 * Decolorizes the given color.
 * @param {String} color HTML string containing the HTML color code.
 * @type String
 * @return Returns a HTML color string
 */
JXG.rgb2bw = function(color) {
    if(color == 'none') {
        return color;
    }
    var x, HexChars="0123456789ABCDEF", tmp, arr;
    arr = JXG.rgbParser(color);
    x = 0.3*arr[0] + 0.59*arr[1] + 0.11*arr[2];
    tmp = HexChars.charAt((x>>4)&0xf)+HexChars.charAt(x&0xf);
    color = "#" + tmp + "" + tmp + "" + tmp;
    return color;
};

/**
 * Converts a color into how a colorblind human approximately would see it.
 * @param {String} color HTML string containing the HTML color code.
 * @param {String} deficiency The type of color blindness. Possible
 * options are <i>protanopia</i>, <i>deuteranopia</i>, and <i>tritanopia</i>.
 * @type String
 * @return Returns a HTML color string
 */
JXG.rgb2cb = function(color, deficiency) {
    if(color == 'none') {
        return color;
    }

    var rgb, l, m, s, lms, tmp,
        a1, b1, c1, a2, b2, c2,
        inflection;

    lms = JXG.rgb2LMS(color);
    l = lms.l; m = lms.m; s = lms.s;

    deficiency = deficiency.toLowerCase();

    switch(deficiency) {
        case "protanopia":
            a1 = -0.06150039994295001;
            b1 = 0.08277001656812001;
            c1 = -0.013200141220000003;
            a2 = 0.05858939668799999;
            b2 = -0.07934519995360001;
            c2 = 0.013289415272000003;
            inflection = 0.6903216543277437;

            tmp = s/m;
            if (tmp < inflection)
                l = -(b1 * m + c1 * s) / a1;
            else
                l = -(b2 * m + c2 * s) / a2;
            break;
        case "tritanopia":
            a1 = -0.00058973116217;
            b1 = 0.007690316482;
            c1 = -0.01011703519052;
            a2 = 0.025495080838999994;
            b2 = -0.0422740347;
            c2 = 0.017005316784;
            inflection = 0.8349489908460004;

            tmp = m / l;
            if (tmp < inflection)
              s = -(a1 * l + b1 * m) / c1;
            else
              s = -(a2 * l + b2 * m) / c2;
            break;
        default:
            a1 = -0.06150039994295001;
            b1 = 0.08277001656812001;
            c1 = -0.013200141220000003;
            a2 = 0.05858939668799999;
            b2 = -0.07934519995360001;
            c2 = 0.013289415272000003;
            inflection = 0.5763833686400911;

            tmp = s/l;
            if(tmp < inflection)
                m = -(a1 * l + c1 * s) / b1;
            else
                m = -(a2 * l + c2 * s) / b2;
            break;
    }

    rgb = JXG.LMS2rgb(l, m, s);

    var HexChars="0123456789ABCDEF";
    tmp = HexChars.charAt((rgb.r>>4)&0xf)+HexChars.charAt(rgb.r&0xf);
    color = "#" + tmp;
    tmp = HexChars.charAt((rgb.g>>4)&0xf)+HexChars.charAt(rgb.g&0xf);
    color += tmp;
    tmp = HexChars.charAt((rgb.b>>4)&0xf)+HexChars.charAt(rgb.b&0xf);
    color += tmp;

    return color;
};


/*
    Copyright 2012
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Alfred Wassermann

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

JXG.extend(JXG.Board.prototype, /** @lends JXG.Board.prototype */ {
    intersection: function(el1, el2, i, j, pointObj){ 
        var p;
        
        el1 = JXG.getReference(this,el1);
        el2 = JXG.getReference(this,el2);
        
        // Get access to the intersection point object
        // This is necessary to read the property alwaysIntersect
        // see JXG.createIntersectionPoint() (Point.js)
        if (pointObj!=null) {
            p = pointObj.point;
        }
        
        if (el1.elementClass==JXG.OBJECT_CLASS_CURVE 
            && el2.elementClass==JXG.OBJECT_CLASS_CURVE
            && (el1.type!=JXG.OBJECT_TYPE_ARC 
                || el2.type!=JXG.OBJECT_TYPE_ARC) ) {
                    
            // curve - curve, but not both are arcs 
            // TEMPORARY FIX!!!
            return function(){
                        return JXG.Math.Geometry.meetCurveCurve(el1,el2,i,j,el1.board); 
                    };
            
        } else if ( (el1.type==JXG.OBJECT_TYPE_ARC 
                      && el2.elementClass==JXG.OBJECT_CLASS_LINE) 
                    ||
                     (el2.type==JXG.OBJECT_TYPE_ARC 
                      && el1.elementClass==JXG.OBJECT_CLASS_LINE)) {
                          
            // arc - line   (arcs are of class curve, but are intersected like circles)
            // TEMPORARY FIX!!!
            return function(){
                        return JXG.Math.Geometry.meet(el1.stdform,el2.stdform,i,el1.board); 
                    };
                    
        } else if ( (el1.elementClass==JXG.OBJECT_CLASS_CURVE 
                      && el2.elementClass==JXG.OBJECT_CLASS_LINE)
                    ||
                     (el2.elementClass==JXG.OBJECT_CLASS_CURVE 
                      && el1.elementClass==JXG.OBJECT_CLASS_LINE)) {
                          
            // curve - line (this includes intersections between conic sections and lines
            return function(){
                        return JXG.Math.Geometry.meetCurveLine(el1,el2,i,el1.board, pointObj); 
                    };
                    
        } else if (el1.elementClass==JXG.OBJECT_CLASS_LINE 
                    && el2.elementClass==JXG.OBJECT_CLASS_LINE
                   )  {
                     
            // line - line, lines may also be segments.
            return function(){ 
                var res, c,
                    first1 = el1.visProp.straightfirst;
                    first2 = el2.visProp.straightfirst;
                    last1 = el1.visProp.straightlast;
                    last2 = el2.visProp.straightlast;

                /** 
                 * If one of the lines is a segment or ray and
                 * the the intersection point shpould disappear if outside 
                 * of the segment or ray we call
                 * meetSegmentSegment 
                 */
                if (JXG.exists(p) && !p.visProp.alwaysintersect
                    && (first1==false
                        || last1==false
                        || first2==false
                        || last2==false)
                    ) {

                    res = JXG.Math.Geometry.meetSegmentSegment(
                        el1.point1.coords.usrCoords, el1.point2.coords.usrCoords,
                        el2.point1.coords.usrCoords, el2.point2.coords.usrCoords, 
                        el1.board); 
                        
                    if ( (!first1 && res[1]<0)
                         || (!last1 && res[1]>1)
                         || (!first2 && res[2]<0)
                         || (!last2 && res[2]>1) ) {
                        c = [0,NaN,NaN];  // Non-existent
                    } else {
                        c = res[0];
                    }
                    return (new JXG.Coords(JXG.COORDS_BY_USER, c, el1.board));
                } else {
                    return JXG.Math.Geometry.meet(el1.stdform,el2.stdform,i,el1.board);
                }
            };
        // All other combinations of circles and lines
        } else {
            return function(){return JXG.Math.Geometry.meet(el1.stdform,el2.stdform,i,el1.board); };
        }
    }, //returns a single point of intersection
    intersectionFunc: function(el1,el2,i,j){ return this.intersection(el1,el2,i,j); },

    /**
    * Intersection of circles and line
    */ 
    otherIntersection: function(el1,el2,el){ 
        el1 = JXG.getReference(this,el1);
        el2 = JXG.getReference(this,el2);
        return function(){
            var c = JXG.Math.Geometry.meet(el1.stdform,el2.stdform,0,el1.board);
            if (Math.abs(el.X()-c.usrCoords[1])>JXG.Math.eps ||
                Math.abs(el.Y()-c.usrCoords[2])>JXG.Math.eps ||
                Math.abs(el.Z()-c.usrCoords[0])>JXG.Math.eps) {
                return c;
            } else {
                return JXG.Math.Geometry.meet(el1.stdform,el2.stdform,1,el1.board);
            }
        };
    }, //returns a single point of intersection
});


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

JXG.extend(JXG.Board.prototype, /** @lends JXG.Board.prototype */ {
    angle: function(A, B, C){ return JXG.Math.Geometry.angle(A,B,C); },
    rad: function(A, B, C){ return JXG.Math.Geometry.rad(A,B,C); },
    distance: function(arr1, arr2){ return JXG.Math.Geometry.distance(arr1,arr2); },
    pow: function(a, b){ return JXG.Math.pow(a,b); },
    round: function(x, n){ return (x).toFixed(n); },
    cosh: function(x){ return JXG.Math.cosh(x); },
    sinh: function(x){ return JXG.Math.sinh(x); },
    sgn: function(x) { return (x==0 ? 0 : x/(Math.abs(x))); },
    D: function(f,obj){ return JXG.Math.Numerics.D(f,obj); },
    I: function(interval,f){ return JXG.Math.Numerics.I(interval,f); },
    root: function(f,x,obj){ return JXG.Math.Numerics.root(f,x,obj); },
    lagrangePolynomial: function(p){ return JXG.Math.Numerics.lagrangePolynomial(p); },
    neville: function(p){ return JXG.Math.Numerics.Neville(p); },
    riemannsum: function(f,n,type,start,end){ return JXG.Math.Numerics.riemannsum(f,n,type,start,end); },

    abs: Math.abs,
    acos: Math.acos,
    asin: Math.asin,
    atan: Math.atan,
    ceil: Math.ceil,
    cos: Math.cos,
    exp: Math.exp,
    floor: Math.floor,
    log: Math.log,
    max: Math.max,
    min: Math.min,
    random: Math.random,
    sin: Math.sin,
    sqrt: Math.sqrt,
    tan: Math.tan,
    trunc: Math.ceil,
    
    factorial: function(n){ return JXG.Math.factorial(n); },
    binomial: function(n,k){ return JXG.Math.binomial(n,k); },

    getElement: function (el) {return JXG.getReference(this,el); },

    /**
     * GUI interface
     **/
    intersectionOptions: ['point',[[JXG.OBJECT_CLASS_LINE,JXG.OBJECT_CLASS_LINE],[JXG.OBJECT_CLASS_LINE,JXG.OBJECT_CLASS_CIRCLE],
                                   [JXG.OBJECT_CLASS_CIRCLE,JXG.OBJECT_CLASS_CIRCLE]]],

    pointFunc: function(){return [null];},
    pointOptions: ['point',[[JXG.OBJECT_CLASS_POINT]]],

    lineFunc: function(){return arguments;},
    lineOptions: ['line',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],

    linesegmentFunc: function(){return arguments;},
    linesegmentOptions: ['line',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],
    linesegmentAtts: {straightFirst : false, straightLast : false },

    arrowFunc: function(){return arguments;},
    arrowOptions: ['arrow',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],

    circleFunc: function(){return arguments;},
    circleOptions: ['circle',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT],[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_LINE],
                              [JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_CIRCLE]]],

    arrowparallelOptions: ['arrowparallel',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_LINE]]],
    arrowparallelFunc: function(){return arguments;},

    bisectorOptions: ['bisector',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],
    bisectorFunc: function(){return arguments;},

    circumcircleOptions: ['circumcircle',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],
    circumcircleFunc: function(){return arguments;},

    circumcirclemidpointOptions: ['circumcirclemidpoint',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],
    circumcirclemidpointFunc: function(){return arguments;},

    integralOptions: ['integral',[[]]],
    integralFunc: function(){return arguments;},

    midpointOptions: ['midpoint',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT],[JXG.OBJECT_CLASS_LINE]]],
    midpointFunc: function(){return arguments;},

    mirrorpointOptions: ['mirrorpoint',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],
    mirrorpointFunc: function(){return arguments;},

    normalOptions: ['normal',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_LINE]]],
    normalFunc: function(){return arguments;},

    parallelOptions: ['parallel',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_LINE]]],
    parallelFunc: function(){return arguments;},

    parallelpointOptions: ['parallelpoint',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_POINT]]],
    parallelpointFunc: function(){return arguments;},

    perpendicularOptions: ['perpendicular',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_LINE]]],
    perpendicularFunc: function(){return arguments;},

    perpendicularpointOptions: ['perpendicularpoint',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_LINE]]],
    perpendicularpointFunc: function(){return arguments;},

    reflectionOptions: ['reflection',[[JXG.OBJECT_CLASS_POINT,JXG.OBJECT_CLASS_LINE]]],
    reflectionFunc: function(){return arguments;}
});

// Some shortcuts
JXG.Point.prototype.setPositionX = function (method, x) {
    var y = (method==JXG.COORDS_BY_USER)?this.coords.usrCoords[2]:this.coords.scrCoords[2];
    this.setPosition(method,[x,y]);
};
JXG.Point.prototype.setPositionY = function (method, y) {
    var x = (method==JXG.COORDS_BY_USER)?this.coords.usrCoords[1]:this.coords.scrCoords[1];
    this.setPosition(method,[x,y]);
};


/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview In this file the geometry object Ticks is defined. Ticks provides
 * methods for creation and management of ticks on an axis.
 * @author graphjs
 * @version 0.1
 */

/**
 * Creates ticks for an axis.
 * @class Ticks provides methods for creation and management
 * of ticks on an axis.
 * @param {JXG.Line} line Reference to the axis the ticks are drawn on.
 * @param {Number|Array} ticks Number defining the distance between two major ticks or an array defining static ticks.
 * @param {Object} attributes Properties
 * @see JXG.Line#addTicks
 * @constructor
 * @extends JXG.GeometryElement
 */
JXG.Ticks = function (line, ticks, attributes) {
    this.constructor(line.board, attributes, JXG.OBJECT_TYPE_TICKS, JXG.OBJECT_CLASS_OTHER);

    /**
     * The line the ticks belong to.
     * @type JXG.Line
     */
    this.line = line;

    /**
     * The board the ticks line is drawn on.
     * @type JXG.Board
     */
    this.board = this.line.board;

    /**
     * A function calculating ticks delta depending on the ticks number.
     * @type Function
     */
    this.ticksFunction = null;

    /**
     * Array of fixed ticks.
     * @type Array
     */
    this.fixedTicks = null;

    /**
     * Equidistant ticks. Distance is defined by ticksFunction
     * @type Boolean
     */
    this.equidistant = false;

    if(JXG.isFunction(ticks)) {
        this.ticksFunction = ticks;
        throw new Error("Function arguments are no longer supported.");
    } else if(JXG.isArray(ticks)) {
        this.fixedTicks = ticks;
    } else {
        if(Math.abs(ticks) < JXG.Math.eps)
            ticks = attributes.defaultdistance;
        this.ticksFunction = function (i) { return ticks; };
        this.equidistant = true;
    }

    /**
     * Least distance between two ticks, measured in pixels.
     * @type int
     */
    this.minTicksDistance = attributes.minticksdistance;

    /**
     * Maximum distance between two ticks, measured in pixels. Is used only when insertTicks
     * is set to true.
     * @type int
     * @see #insertTicks
     * @deprecated This value will be ignored.
     */
    this.maxTicksDistance = attributes.maxticksdistance;

    /**
     * Array where the labels are saved. There is an array element for every tick,
     * even for minor ticks which don't have labels. In this case the array element
     * contains just <tt>null</tt>.
     * @type Array
     */
    this.labels = [];

    this.id = this.line.addTicks(this);
    this.board.setId(this,'Ti');
};

JXG.Ticks.prototype = new JXG.GeometryElement();

JXG.extend(JXG.Ticks.prototype, /** @lends JXG.Ticks.prototype */ {
    /**
     * Checks whether (x,y) is near the line.
     * @param {Number} x Coordinate in x direction, screen coordinates.
     * @param {Number} y Coordinate in y direction, screen coordinates.
     * @return {Boolean} True if (x,y) is near the line, False otherwise.
     */
    hasPoint: function (x, y) {
        var i, t,
            len = this.ticks.length,
            r = this.board.options.precision.hasPoint;
            
        if (!this.line.visProp.scalable) {
            return false;
        }
        
        // Ignore non-axes and axes that are not horizontal or vertical
        if (this.line.stdform[1]!=0 
            && this.line.stdform[2]!=0
            && this.line.type!=JXG.OBJECT_TYPE_AXIS) {  
            
            return false;
        }

        for (i=0; i<len; i++) {
            t = this.ticks[i];
            if (!t[2]) continue;       // Skip minor ticks
            
            // Ignore ticks at zero
            if (this.line.stdform[1]==0 && Math.abs(t[0][0]-this.line.point1.coords.scrCoords[1])<JXG.Math.eps) {
                continue;
            } else if (this.line.stdform[2]==0 && Math.abs(t[1][0]-this.line.point1.coords.scrCoords[2])<JXG.Math.eps) {
                continue;
            }
                
            if (Math.abs(t[0][0]-t[0][1])>=1 || Math.abs(t[1][0]-t[1][1])>=1) {    // tick length is not zero, ie. at least one pixel
                /*
                if (t[0][0]-r < x 
                    && x < t[0][1]+r 
                    && t[1][0]-r < y 
                    && y < t[1][1]+r) {
                
                    return true;
                }
                */
                if (this.line.stdform[1]==0) {
                    if (Math.abs(y - (t[1][0]+t[1][1])*0.5) < 2*r    // Allow dragging near axes only.
                        && t[0][0]-r < x
                        && x < t[0][1]+r) {
                
                        return true;
                    }
                } else if  (this.line.stdform[2]==0) {
                    if (Math.abs(x - (t[0][0]+t[0][1])*0.5) < 2*r  
                        && t[1][0]-r < y
                        && y < t[1][1]+r) {
                
                        return true;
                    }
                }
            }
        }
        
       return false;
    },

    setPositionDirectly: function (method, coords, oldcoords) {
        var dx, dy, i, 
            c = new JXG.Coords(method, coords, this.board),
            oldc = new JXG.Coords(method, oldcoords, this.board),
            bb = this.board.getBoundingBox();

        
        if (!this.line.visProp.scalable) {
            return this;
        }
        
        if (Math.abs(this.line.stdform[1])<JXG.Math.eps         // horizontal line     
            && Math.abs(c.usrCoords[1]*oldc.usrCoords[1])>JXG.Math.eps) {  
            dx =oldc.usrCoords[1] / c.usrCoords[1];
            bb[0] *= dx;
            bb[2] *= dx;
            this.board.setBoundingBox(bb, false);
        } else if (Math.abs(this.line.stdform[2])<JXG.Math.eps // vertical line
            && Math.abs(c.usrCoords[2]*oldc.usrCoords[2])>JXG.Math.eps) { 
            dy = oldc.usrCoords[2] / c.usrCoords[2];
            bb[3] *= dy;
            bb[1] *= dy;
            this.board.setBoundingBox(bb, false);
        }
        //this.board.mode = this.board.BOARD_MODE_DRAG;
        //this.board.needsFullUpdate = true;
        
        return this;
    },
    

    /**
     * (Re-)calculates the ticks coordinates.
     */
    calculateTicksCoordinates: function() {
            // Point 1 of the line
        var p1 = this.line.point1,
            // Point 2 of the line
            p2 = this.line.point2,
            // Distance between the two points from above
            distP1P2 = p1.Dist(p2),
            // Distance of X coordinates of two major ticks
            // Initialized with the distance of Point 1 to a point between Point 1 and Point 2 on the line and with distance 1
            // this equals always 1 for lines parallel to x = 0 or y = 0. It's only important for lines other than that.
            deltaX = (p2.coords.usrCoords[1] - p1.coords.usrCoords[1])/distP1P2,
            // The same thing for Y coordinates
            deltaY = (p2.coords.usrCoords[2] - p1.coords.usrCoords[2])/distP1P2,
            // Distance of p1 to the unit point in screen coordinates
            distScr = p1.coords.distance(JXG.COORDS_BY_SCREEN, new JXG.Coords(JXG.COORDS_BY_USER, [p1.coords.usrCoords[1] + deltaX, p1.coords.usrCoords[2] + deltaY], this.board)),
            // Distance between two major ticks in user coordinates
            ticksDelta = (this.equidistant ? this.ticksFunction(1) : 1),
            symbTicksDelta, f,
            // This factor is for enlarging ticksDelta and it switches between 5 and 2
            // Hence, if two major ticks are too close together they'll be expanded to a distance of 5
            // if they're still too close together, they'll be expanded to a distance of 10 etc
            factor = 5,
            // Coordinates of the current tick
            tickCoords,
            // Coordinates of the first drawn tick
            startTick,
            symbStartTick,
            // two counters
            i, j,
            // the distance of the tick to p1. Is displayed on the board using a label
            // for majorTicks
            tickPosition,
            symbTickPosition,
            // infinite or finite tick length
            style,
            // new position
            nx = 0,
            ny = 0,
            ti,
			dirs = 2, dir = -1, 
			center, d, bb, perp,
            
            // the following variables are used to define ticks height and slope
            eps = JXG.Math.eps, pos, lb, ub,
            distMaj = this.visProp.majorheight * 0.5,
            distMin = this.visProp.minorheight * 0.5,
            // ticks width and height in screen units
            dxMaj, dyMaj,
            dxMin, dyMin,
            // ticks width and height in user units
            dx, dy;
        // END OF variable declaration

        // This will trap this update routine in an endless loop. Besides, there's not much we can show
        // on such a tiny board, so we just get out of here immediately.
        if (this.board.canvasWidth === 0 || this.board.canvasHeight === 0) {
            return;
        }

        // Grid-like ticks
        if (this.visProp.minorheight < 0)  {
            this.minStyle = 'infinite';
        } else {
            this.minStyle = 'finite';
        }
            
        if(this.visProp.majorheight < 0) {
            this.majStyle = 'infinite';
        } else {
            this.majStyle = 'finite';
        }

        // Set lower and upper bound for the tick distance.
        // This is necessary for segments.
        if (this.line.visProp.straightfirst) {
            lb = Number.NEGATIVE_INFINITY;
        } else {
            lb = 0 + eps;
        }

        if (this.line.visProp.straightlast) {
            ub = Number.POSITIVE_INFINITY;
        } else {
            ub = distP1P2 - eps;
        }

        // This piece of code used to be in AbstractRenderer.updateAxisTicksInnerLoop
        // and has been moved in here to clean up the renderers code.
        //
        // The code above only calculates the position of the ticks. The following code parts
        // calculate the dx and dy values which make ticks out of this positions, i.e. from the
        // position (p_x, p_y) calculated above we have to draw a line from
        // (p_x - dx, py - dy) to (p_x + dx, p_y + dy) to get a tick.
        dxMaj = this.line.stdform[1];
        dyMaj = this.line.stdform[2];
        dxMin = dxMaj;
        dyMin = dyMaj;
        dx = dxMaj;
        dy = dyMaj;
        
        // After this, the length of the vector (dxMaj, dyMaj) in screen coordinates is equal to distMaj pixel.
        d = Math.sqrt(dxMaj*dxMaj*this.board.unitX*this.board.unitX + dyMaj*dyMaj*this.board.unitY*this.board.unitY);
        dxMaj *= distMaj/d*this.board.unitX;
        dyMaj *= distMaj/d*this.board.unitY;
        dxMin *= distMin/d*this.board.unitX;
        dyMin *= distMin/d*this.board.unitY;

        // Begin cleanup
        this.removeTickLabels();
        
        // If the parent line is not finite, we can stop here.
        if (Math.abs(dx)<JXG.Math.eps && Math.abs(dy)<JXG.Math.eps) {
            return;
        }

        // initialize storage arrays
        // ticks stores the ticks coordinates
        this.ticks = [];
        
        // labels stores the text to display beside the ticks
        this.labels = [];
        // END cleanup
        
        // we have an array of fixed ticks we have to draw
        if (!this.equidistant) {
            for (i = 0; i < this.fixedTicks.length; i++) {
                nx = p1.coords.usrCoords[1] + this.fixedTicks[i]*deltaX;
                ny = p1.coords.usrCoords[2] + this.fixedTicks[i]*deltaY;
                tickCoords = new JXG.Coords(JXG.COORDS_BY_USER, [nx, ny], this.board);
                
                ti = this._tickEndings(tickCoords, dx, dy, dxMaj, dyMaj, dxMin, dyMin, /*major:*/ true);
				// Compute the start position and the end position of a tick.
				// If both positions are out of the canvas, ti is empty.
                if (ti.length==2 && this.fixedTicks[i]>=lb && this.fixedTicks[i]<ub) {
                    this.ticks.push(ti);
                }
                this.labels.push(this._makeLabel(this.visProp.labels[i] || this.fixedTicks[i], tickCoords, this.board, this.visProp.drawlabels, this.id, i));
                // visibility test missing
            }
            return;
        }

        symbTicksDelta = ticksDelta;
        ticksDelta *= this.visProp.scale;

        // ok, we have equidistant ticks and not special ticks, so we continue here with generating them:
        // adjust distances
        if (this.visProp.insertticks && this.minTicksDistance > JXG.Math.eps) {
            f = this._adjustTickDistance(ticksDelta, distScr, factor, p1.coords, deltaX, deltaY);
            ticksDelta *= f;
            symbTicksDelta *= f;
        }

        if (!this.visProp.insertticks) {
            ticksDelta /= this.visProp.minorticks+1;
            symbTicksDelta /= this.visProp.minorticks+1;
        }

        this.ticksDelta = ticksDelta;
        this.symbTicksDelta = symbTicksDelta;


		// We shoot into the middle of the canvas
		// to the tick position which is closest to the center
		// of the canvas. We do this by an orthogonal projection
		// of the canvas center to the line and by rounding of the
		// distance of the projected point to point1 of the line.
		// This position is saved in
		// center and startTick.
        bb = this.board.getBoundingBox();
        nx = (bb[0]+bb[2])*0.5;
        ny = (bb[1]+bb[3])*0.5;
		
		// Project the center of the canvas to the line.
		perp = [nx*this.line.stdform[2]-ny*this.line.stdform[1], 
				-this.line.stdform[2], 
				 this.line.stdform[1]];
		center = JXG.Math.crossProduct(this.line.stdform, perp);
		center[1] /= center[0];
		center[2] /= center[0];
		center[0] = 1;
		// Round the distance of center to point1
        tickCoords = new JXG.Coords(JXG.COORDS_BY_USER, center.slice(1), this.board);
        d = p1.coords.distance(JXG.COORDS_BY_USER, tickCoords);
        if ((p2.X()-p1.X())*(center[1]-p1.X())<0 || (p2.Y()-p1.Y())*(center[2]-p1.Y())<0) {
            d *= -1;
        }
        tickPosition = Math.round(d/ticksDelta)*ticksDelta;

		// Find the correct direction of center from point1
        if (Math.abs(tickPosition)>JXG.Math.eps) {
            dir = Math.abs(tickPosition)/tickPosition;
        }
		// From now on, we jump around center
        center[1] = p1.coords.usrCoords[1] + deltaX*tickPosition;
        center[2] = p1.coords.usrCoords[2] + deltaY*tickPosition;
        startTick = tickPosition;
        tickPosition = 0;

        symbTickPosition = 0;
        // this could be done more elaborate to prevent rounding errors
        symbStartTick = startTick/this.visProp.scale;

        nx = center[1];
        ny = center[2];
        i = 0;          // counter for label ids
        j = 0;
		// Now, we jump around center
		// until we are outside of the canvas.
		// If this is the case we proceed in the other
		// direction until we are out of the canvas in this direction, too.
		// Then we are done.
        do {
            tickCoords = new JXG.Coords(JXG.COORDS_BY_USER, [nx, ny], this.board);

			// Test if tick is a major tick.
            // This is the case if (dir*tickPosition+startTick)/ticksDelta is
            // a multiple of the number of minorticks+1
            tickCoords.major = Math.round((dir * tickPosition + startTick) / ticksDelta) % (this.visProp.minorticks + 1) === 0;
            
			// Compute the start position and the end position of a tick.
			// If both positions are out of the canvas, ti is empty.
            ti = this._tickEndings(tickCoords, dx, dy, dxMaj, dyMaj, dxMin, dyMin, tickCoords.major);
            
            // The tick has an overlap with the board?
            if (ti.length === 3) {
                pos = dir*symbTickPosition+symbStartTick;
                if ((Math.abs(pos) >= eps || this.visProp.drawzero) && (pos > lb && pos < ub)) {
                    this.ticks.push(ti);
                    
                    if (tickCoords.major) {
                        this.labels.push(this._makeLabel(pos, tickCoords, this.board, this.visProp.drawlabels, this.id, i));
                    } else {
                        this.labels.push(null);
                    }
                    i++;
                }
                
                // Toggle direction
                if (dirs==2) {
                    dir *= (-1);
                }
				// Increase distance from center
                if (j % 2 === 0 || dirs === 1) {
                    tickPosition += ticksDelta;
                    symbTickPosition += symbTicksDelta;
                }
            } else {
                dir *= (-1);
                dirs--;
            }

            j++;
            
            nx = center[1] + dir*deltaX*tickPosition;
            ny = center[2] + dir*deltaY*tickPosition;
        } while (dirs>0);

        this.needsUpdate = true;
        this.updateRenderer();
    },
    
    /**
     * @private
     */
    _adjustTickDistance: function(ticksDelta, distScr, factor, p1c, deltaX, deltaY) {
        var nx, ny, f = 1;
        
        while (distScr > 4*this.minTicksDistance) {
            f /= 10;
            nx = p1c.usrCoords[1] + deltaX*ticksDelta*f;
            ny = p1c.usrCoords[2] + deltaY*ticksDelta*f;
            distScr = p1c.distance(JXG.COORDS_BY_SCREEN, new JXG.Coords(JXG.COORDS_BY_USER, [nx, ny], this.board));
        }

        // If necessary, enlarge ticksDelta
        while (distScr < this.minTicksDistance) {
            f *= factor;
            factor = (factor == 5 ? 2 : 5);
            nx = p1c.usrCoords[1] + deltaX*ticksDelta*f;
            ny = p1c.usrCoords[2] + deltaY*ticksDelta*f;
            distScr = p1c.distance(JXG.COORDS_BY_SCREEN, new JXG.Coords(JXG.COORDS_BY_USER, [nx, ny], this.board));
        }
        return f;
    },

    /**
     * @param {JXG.Coords} coords Coordinates of the tick on the line.
     * @param {Number} dx horizontal tick extension in user coordinates.
     * @param {Number} dy vertical tick extension in user coordinates.
     * @param {Number} dxMaj horizontal tick direction in screen coordinates.
     * @param {Number} dyMaj vertical tick direction in screen coordinates.
     * @param {Number} dxMin horizontal tick direction in screen coordinates.
     * @param {Number} dyMin vertical tick direction in screen coordinates.
     * @param {Boolean} major True if tick is major tick.
     * @return {Array} Array of length 3 containing start and end coordinates in screen coordinates
     *                 of the tick (arrays of length 2). 3rd entry is true if major tick otherwise false.
     *                 If the tick is outside of the canvas, the return array is empty.
     * @private
     */
    _tickEndings: function(coords, dx, dy, dxMaj, dyMaj, dxMin, dyMin, major) {
        var i, c, 
            cw = this.board.canvasWidth,
            ch = this.board.canvasHeight,
            x = [-1000*cw, -1000*ch],
            y = [-1000*cw, -1000*ch], 
            dxs, dys,
            s, style,
            count = 0,
            isInsideCanvas = false;

		c = coords.scrCoords;
		if (major) {
			dxs = dxMaj;
			dys = dyMaj;
			style = this.majStyle;
		} else {
			dxs = dxMin;
			dys = dyMin;
			style = this.minStyle;
		}
        
		// This is necessary to compute the correct direction of infinite grid lines
		// if unitX!=unitY.
		//dxs = dx; //*this.board.unitX;
		//dys = dy; //*this.board.unitY;

		// For all ticks regardless if of finite or infinite
		// tick length the intersection with the canvas border is 
		// computed. 
		
		// horizontal line and vertical tick 
		if (Math.abs(dx)<JXG.Math.eps) {
			x[0] = c[1];
			x[1] = c[1];
			y[0] = 0;
			y[1] = ch;
		// vertical line and horizontal tick
		} else if (Math.abs(dy)<JXG.Math.eps) {
			x[0] = 0;
			x[1] = cw;
			y[0] = c[2];
			y[1] = c[2];
        // other
		} else {
			count = 0;
			s = JXG.Math.crossProduct([0,0,1], [-dys*c[1]-dxs*c[2], dys, dxs]); // intersect with top
			s[1] /= s[0];
			if (s[1]>=0 && s[1]<=cw) {  
				x[count] = s[1];
				y[count] = 0;
				count++;
			}
			s = JXG.Math.crossProduct([0,1,0], [-dys*c[1]-dxs*c[2], dys, dxs]); // intersect with left
			s[2] /= s[0];
			if (s[2]>=0 && s[2]<=ch) {  
				x[count] = 0;
				y[count] = s[2];
				count++;
			}
			if (count<2) {
				s = JXG.Math.crossProduct([ch*ch,0,-ch], [-dys*c[1]-dxs*c[2], dys, dxs]); // intersect with bottom
				s[1] /= s[0];
				if (s[1]>=0 && s[1]<=cw) {  
					x[count] = s[1];
					y[count] = ch;
					count++;
				}
			}
			if (count<2) {
				s = JXG.Math.crossProduct([cw*cw, -cw, 0], [-dys*c[1]-dxs*c[2], dys, dxs]); // intersect with right
				s[2] /= s[0];
				if (s[2]>=0 && s[2]<=ch) {  
					x[count] = cw;
					y[count] = s[2];
				}
			}
		}
		if ((x[0]>=0 && x[0]<=cw && y[0]>=0 && y[0]<=ch ) 
			|| 
			(x[1]>=0 && x[1]<=cw && y[1]>=0 && y[1]<=ch)
		   ) {
			isInsideCanvas = true;
		} else { 
			isInsideCanvas = false;
		}
		// finite tick length
		if (style=='finite') {
			x[0] = c[1] + dxs;
			y[0] = c[2] - dys;
			x[1] = c[1] - dxs;
			y[1] = c[2] + dys;
		}
        if (isInsideCanvas) {
            return [x,y, major];
        } else { 
            return [];
        }
    },

    /** 
     * Create a tick label 
     * @private
     **/
    _makeLabel: function(pos, newTick, board, drawLabels, id, i) {
        var labelText, label, attr, num = typeof pos === 'number';

        if (!drawLabels) {
            return null;
        }

        labelText = pos.toString();
        if (Math.abs(pos) < JXG.Math.eps) {
            labelText = '0';
        }

        if(num && (labelText.length > 5 || labelText.indexOf('e') != -1)) {
            labelText = pos.toPrecision(3).toString();
        }
        if (num && labelText.indexOf('.') > -1) {
            // trim trailing zeros
            labelText = labelText.replace(/0+$/, '');
            // trim trailing .
            labelText = labelText.replace(/\.$/, '');
        }

        if (this.visProp.scalesymbol.length > 0 && labelText === '1') {
            labelText = this.visProp.scalesymbol;
        } else if (this.visProp.scalesymbol.length > 0 && labelText === '0') {
            labelText = '0';
        } else {
            labelText = labelText + this.visProp.scalesymbol;
        }

        attr = {
            id: id + i + 'Label',
            isLabel: true,
            layer: board.options.layer.line,
            highlightStrokeColor: board.options.text.strokeColor,
            highlightStrokeWidth: board.options.text.strokeWidth,
            highlightStrokeOpacity: board.options.text.strokeOpacity,
            visible: this.visProp.visible,
            priv: this.visProp.priv
        };
        attr = JXG.deepCopy(attr, this.visProp.label);
        label = JXG.createText(board, [newTick.usrCoords[1], newTick.usrCoords[2], labelText], attr);
        label.isDraggable = false;
        label.dump = false;

        /*
         * Ticks have their own label handling which is done below and not
         * in Text.update().
         * The reason is that there is no parent element for the labels
         * which can determine the label position.
         */
        //label.distanceX = 4;
        //label.distanceY = -parseInt(label.visProp.fontsize)+3; //-9;
        label.distanceX = this.visProp.label.offset[0];
        label.distanceY = this.visProp.label.offset[1];
        label.setCoords(newTick.usrCoords[1] + label.distanceX / (board.unitX),
            newTick.usrCoords[2] + label.distanceY / (board.unitY));

        label.visProp.visible = drawLabels;
        //label.prepareUpdate().update().updateRenderer();
        return label;
    },

    /**
     * Removes the HTML divs of the tick labels
     * before repositioning
     * @private
     */
    removeTickLabels: function () {
        var j;

        // remove existing tick labels
        if(this.labels != null) {
            if ((this.board.needsFullUpdate||this.needsRegularUpdate) &&
                !(this.board.options.renderer=='canvas'&&this.board.options.text.display=='internal')
               ) {
                for(j=0; j<this.labels.length; j++) {
                    if(this.labels[j] != null) {
                        this.board.removeObject(this.labels[j]);
                    }
                }
            }
        }
    },

    /**
     * Recalculate the tick positions and the labels.
     */
    update: function () {
        if (this.needsUpdate) {
            this.calculateTicksCoordinates();
        }
        return this;
    },

    /**
     * Uses the boards renderer to update the arc.
     */
    updateRenderer: function () {
        if (this.needsUpdate) {
            if (this.ticks) {
                this.board.renderer.updateTicks(this, this.dxMaj, this.dyMaj, this.dxMin, this.dyMin, this.minStyle, this.majStyle);
            }
            this.needsUpdate = false;
        }
        return this;
    },

    hideElement: function () {
        var i;

        this.visProp.visible = false;
        this.board.renderer.hide(this);

        for (i = 0; i < this.labels.length; i++) {
            if (JXG.exists(this.labels[i]))
                this.labels[i].hideElement();
        }

        return this;
    },

    showElement: function () {
        var i;

        this.visProp.visible = true;
        this.board.renderer.show(this);

        for (i = 0; i < this.labels.length; i++) {
            if (JXG.exists(this.labels[i]))
                this.labels[i].showElement();
        }

        return this;
    }
});

/**
 * @class Ticks are used as distance markers on a line.
 * @pseudo
 * @description
 * @name Ticks
 * @augments JXG.Ticks
 * @constructor
 * @type JXG.Ticks
 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 * @param {JXG.Line,Number} line,_distance The parents consist of the line the ticks are going to be attached to and optional the
 * distance between two major ticks. If no distance is given the attribute {@link JXG.Ticks#ticksDistance} is used.
 * @example
 * // Create an axis providing two coord pairs.
 *   var p1 = board.create('point', [0, 3]);
 *   var p2 = board.create('point', [1, 3]);
 *   var l1 = board.create('line', [p1, p2]);
 *   var t = board.create('ticks', [l1], {ticksDistance: 2});
 * </pre><div id="ee7f2d68-75fc-4ec0-9931-c76918427e63" style="width: 300px; height: 300px;"></div>
 * <script type="text/javascript">
 * (function () {
 *   var board = JXG.JSXGraph.initBoard('ee7f2d68-75fc-4ec0-9931-c76918427e63', {boundingbox: [-1, 7, 7, -1], showcopyright: false, shownavigation: false});
 *   var p1 = board.create('point', [0, 3]);
 *   var p2 = board.create('point', [1, 3]);
 *   var l1 = board.create('line', [p1, p2]);
 *   var t = board.create('ticks', [l1], {ticksDistance: 2});
 * })();
 * </script><pre>
 */
JXG.createTicks = function(board, parents, attributes) {
    var el, dist,
        attr = JXG.copyAttributes(attributes, board.options, 'ticks');

    if (parents.length < 2) {
        dist = attributes.ticksDistance;
    } else {
        dist = parents[1];
    }

    if ( (parents[0].elementClass == JXG.OBJECT_CLASS_LINE) && (JXG.isFunction(parents[1]) || JXG.isArray(parents[1]) || JXG.isNumber(parents[1]))) {
        el = new JXG.Ticks(parents[0], dist, attr);
    } else {
        throw new Error("JSXGraph: Can't create Ticks with parent types '" + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'.");
    }
    
    el.isDraggable = true;

    return el;
};

JXG.JSXGraph.registerElement('ticks', JXG.createTicks);


/*
    Copyright 2008-2012
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.
    
    Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXCompressor.  If not, see <http://www.gnu.org/licenses/>.
    
    You should have received a copy of the Apache License along with JSXCompressor.  
    If not, see <http://www.apache.org/licenses/>.

*/

/**
 * @fileoverview Utilities for uncompressing and base64 decoding
 */

/**
  * @class Util class
  * Class for gunzipping, unzipping and base64 decoding of files.
  * It is used for reading GEONExT, Geogebra and Intergeo files.
  *
  * Only Huffman codes are decoded in gunzip.
  * The code is based on the source code for gunzip.c by Pasi Ojala 
  * @see <a href="http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c">http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c</a>
  * @see <a href="http://www.cs.tut.fi/~albert">http://www.cs.tut.fi/~albert</a>
  */
JXG.Util = {};
                                 
/**
 * Unzip zip files
 */
JXG.Util.Unzip = function (barray){
    var outputArr = [],
        output = "",
        debug = false,
        gpflags,
        files = 0,
        unzipped = [],
        crc,
        buf32k = new Array(32768),
        bIdx = 0,
        modeZIP=false,

        CRC, SIZE,
    
        bitReverse = [
        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
    ],
    
    cplens = [
        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
    ],

    cplext = [
        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
    ], /* 99==invalid */

    cpdist = [
        0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d,
        0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1,
        0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01,
        0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
    ],

    cpdext = [
        0,  0,  0,  0,  1,  1,  2,  2,
        3,  3,  4,  4,  5,  5,  6,  6,
        7,  7,  8,  8,  9,  9, 10, 10,
        11, 11, 12, 12, 13, 13
    ],
    
    border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
    
    bA = barray,

    bytepos=0,
    bitpos=0,
    bb = 1,
    bits=0,
    
    NAMEMAX = 256,
    
    nameBuf = [],
    
    fileout;
    
    function readByte(){
        bits+=8;
        if (bytepos<bA.length){
            //if (debug)
            //    document.write(bytepos+": "+bA[bytepos]+"<br>");
            return bA[bytepos++];
        } else
            return -1;
    };

    function byteAlign(){
        bb = 1;
    };
    
    function readBit(){
        var carry;
        bits++;
        carry = (bb & 1);
        bb >>= 1;
        if (bb==0){
            bb = readByte();
            carry = (bb & 1);
            bb = (bb>>1) | 0x80;
        }
        return carry;
    };

    function readBits(a) {
        var res = 0,
            i = a;
    
        while(i--) {
            res = (res<<1) | readBit();
        }
        if(a) {
            res = bitReverse[res]>>(8-a);
        }
        return res;
    };
        
    function flushBuffer(){
        //document.write('FLUSHBUFFER:'+buf32k);
        bIdx = 0;
    };
    function addBuffer(a){
        SIZE++;
        //CRC=updcrc(a,crc);
        buf32k[bIdx++] = a;
        outputArr.push(String.fromCharCode(a));
        //output+=String.fromCharCode(a);
        if(bIdx==0x8000){
            //document.write('ADDBUFFER:'+buf32k);
            bIdx=0;
        }
    };
    
    function HufNode() {
        this.b0=0;
        this.b1=0;
        this.jump = null;
        this.jumppos = -1;
    };

    var LITERALS = 288;
    
    var literalTree = new Array(LITERALS);
    var distanceTree = new Array(32);
    var treepos=0;
    var Places = null;
    var Places2 = null;
    
    var impDistanceTree = new Array(64);
    var impLengthTree = new Array(64);
    
    var len = 0;
    var fpos = new Array(17);
    fpos[0]=0;
    var flens;
    var fmax;
    
    function IsPat() {
        while (1) {
            if (fpos[len] >= fmax)
                return -1;
            if (flens[fpos[len]] == len)
                return fpos[len]++;
            fpos[len]++;
        }
    };

    function Rec() {
        var curplace = Places[treepos];
        var tmp;
        if (debug)
    		document.write("<br>len:"+len+" treepos:"+treepos);
        if(len==17) { //war 17
            return -1;
        }
        treepos++;
        len++;
    	
        tmp = IsPat();
        if (debug)
        	document.write("<br>IsPat "+tmp);
        if(tmp >= 0) {
            curplace.b0 = tmp;    /* leaf cell for 0-bit */
            if (debug)
            	document.write("<br>b0 "+curplace.b0);
        } else {
        /* Not a Leaf cell */
        curplace.b0 = 0x8000;
        if (debug)
        	document.write("<br>b0 "+curplace.b0);
        if(Rec())
            return -1;
        }
        tmp = IsPat();
        if(tmp >= 0) {
            curplace.b1 = tmp;    /* leaf cell for 1-bit */
            if (debug)
            	document.write("<br>b1 "+curplace.b1);
            curplace.jump = null;    /* Just for the display routine */
        } else {
            /* Not a Leaf cell */
            curplace.b1 = 0x8000;
            if (debug)
            	document.write("<br>b1 "+curplace.b1);
            curplace.jump = Places[treepos];
            curplace.jumppos = treepos;
            if(Rec())
                return -1;
        }
        len--;
        return 0;
    };

    function CreateTree(currentTree, numval, lengths, show) {
        var i;
        /* Create the Huffman decode tree/table */
        //document.write("<br>createtree<br>");
        if (debug)
        	document.write("currentTree "+currentTree+" numval "+numval+" lengths "+lengths+" show "+show);
        Places = currentTree;
        treepos=0;
        flens = lengths;
        fmax  = numval;
        for (i=0;i<17;i++)
            fpos[i] = 0;
        len = 0;
        if(Rec()) {
            //fprintf(stderr, "invalid huffman tree\n");
            if (debug)
            	alert("invalid huffman tree\n");
            return -1;
        }
        if (debug){
        	document.write('<br>Tree: '+Places.length);
        	for (var a=0;a<32;a++){
            	document.write("Places["+a+"].b0="+Places[a].b0+"<br>");
            	document.write("Places["+a+"].b1="+Places[a].b1+"<br>");
        	}
        }
    
        /*if(show) {
            var tmp;
            for(tmp=currentTree;tmp<Places;tmp++) {
                fprintf(stdout, "0x%03x  0x%03x (0x%04x)",tmp-currentTree, tmp->jump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0);
                if(!(tmp.b0 & 0x8000)) {
                    //fprintf(stdout, "  0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�');
                }
                if(!(tmp.b1 & 0x8000)) {
                    if((tmp.b0 & 0x8000))
                        fprintf(stdout, "           ");
                    fprintf(stdout, "  0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�');
                }
                fprintf(stdout, "\n");
            }
        }*/
        return 0;
    };
    
    function DecodeValue(currentTree) {
        var len, i,
            xtreepos=0,
            X = currentTree[xtreepos],
            b;

        /* decode one symbol of the data */
        while(1) {
            b=readBit();
            if (debug)
            	document.write("b="+b);
            if(b) {
                if(!(X.b1 & 0x8000)){
                	if (debug)
                    	document.write("ret1");
                    return X.b1;    /* If leaf node, return data */
                }
                X = X.jump;
                len = currentTree.length;
                for (i=0;i<len;i++){
                    if (currentTree[i]===X){
                        xtreepos=i;
                        break;
                    }
                }
                //xtreepos++;
            } else {
                if(!(X.b0 & 0x8000)){
                	if (debug)
                    	document.write("ret2");
                    return X.b0;    /* If leaf node, return data */
                }
                //X++; //??????????????????
                xtreepos++;
                X = currentTree[xtreepos];
            }
        }
        if (debug)
        	document.write("ret3");
        return -1;
    };
    
    function DeflateLoop() {
    var last, c, type, i, len;

    do {
        /*if((last = readBit())){
            fprintf(errfp, "Last Block: ");
        } else {
            fprintf(errfp, "Not Last Block: ");
        }*/
        last = readBit();
        type = readBits(2);
        switch(type) {
            case 0:
            	if (debug)
                	alert("Stored\n");
                break;
            case 1:
            	if (debug)
                	alert("Fixed Huffman codes\n");
                break;
            case 2:
            	if (debug)
                	alert("Dynamic Huffman codes\n");
                break;
            case 3:
            	if (debug)
                	alert("Reserved block type!!\n");
                break;
            default:
            	if (debug)
                	alert("Unexpected value %d!\n", type);
                break;
        }

        if(type==0) {
            var blockLen, cSum;

            // Stored 
            byteAlign();
            blockLen = readByte();
            blockLen |= (readByte()<<8);

            cSum = readByte();
            cSum |= (readByte()<<8);

            if(((blockLen ^ ~cSum) & 0xffff)) {
                document.write("BlockLen checksum mismatch\n");
            }
            while(blockLen--) {
                c = readByte();
                addBuffer(c);
            }
        } else if(type==1) {
            var j;

            /* Fixed Huffman tables -- fixed decode routine */
            while(1) {
            /*
                256    0000000        0
                :   :     :
                279    0010111        23
                0   00110000    48
                :    :      :
                143    10111111    191
                280 11000000    192
                :    :      :
                287 11000111    199
                144    110010000    400
                :    :       :
                255    111111111    511
    
                Note the bit order!
                */

            j = (bitReverse[readBits(7)]>>1);
            if(j > 23) {
                j = (j<<1) | readBit();    /* 48..255 */

                if(j > 199) {    /* 200..255 */
                    j -= 128;    /*  72..127 */
                    j = (j<<1) | readBit();        /* 144..255 << */
                } else {        /*  48..199 */
                    j -= 48;    /*   0..151 */
                    if(j > 143) {
                        j = j+136;    /* 280..287 << */
                        /*   0..143 << */
                    }
                }
            } else {    /*   0..23 */
                j += 256;    /* 256..279 << */
            }
            if(j < 256) {
                addBuffer(j);
                //document.write("out:"+String.fromCharCode(j));
                /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/
            } else if(j == 256) {
                /* EOF */
                break;
            } else {
                var len, dist;

                j -= 256 + 1;    /* bytes + EOF */
                len = readBits(cplext[j]) + cplens[j];

                j = bitReverse[readBits(5)]>>3;
                if(cpdext[j] > 8) {
                    dist = readBits(8);
                    dist |= (readBits(cpdext[j]-8)<<8);
                } else {
                    dist = readBits(cpdext[j]);
                }
                dist += cpdist[j];

                /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/
                for(j=0;j<len;j++) {
                    var c = buf32k[(bIdx - dist) & 0x7fff];
                    addBuffer(c);
                }
            }
            } // while
        } else if(type==2) {
            var j, n, literalCodes, distCodes, lenCodes;
            var ll = new Array(288+32);    // "static" just to preserve stack
    
            // Dynamic Huffman tables 
    
            literalCodes = 257 + readBits(5);
            distCodes = 1 + readBits(5);
            lenCodes = 4 + readBits(4);
            //document.write("<br>param: "+literalCodes+" "+distCodes+" "+lenCodes+"<br>");
            for(j=0; j<19; j++) {
                ll[j] = 0;
            }
    
            // Get the decode tree code lengths
    
            //document.write("<br>");
            for(j=0; j<lenCodes; j++) {
                ll[border[j]] = readBits(3);
                //document.write(ll[border[j]]+" ");
            }
            //fprintf(errfp, "\n");
            //document.write('<br>ll:'+ll);
            len = distanceTree.length;
            for (i=0; i<len; i++)
                distanceTree[i]=new HufNode();
            if(CreateTree(distanceTree, 19, ll, 0)) {
                flushBuffer();
                return 1;
            }
            if (debug){
            	document.write("<br>distanceTree");
            	for(var a=0;a<distanceTree.length;a++){
                	document.write("<br>"+distanceTree[a].b0+" "+distanceTree[a].b1+" "+distanceTree[a].jump+" "+distanceTree[a].jumppos);
                	/*if (distanceTree[a].jumppos!=-1)
                    	document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1);
                	*/
            	}
            }
            //document.write('<BR>tree created');
    
            //read in literal and distance code lengths
            n = literalCodes + distCodes;
            i = 0;
            var z=-1;
            if (debug)
            	document.write("<br>n="+n+" bits: "+bits+"<br>");
            while(i < n) {
                z++;
                j = DecodeValue(distanceTree);
                if (debug)
                	document.write("<br>"+z+" i:"+i+" decode: "+j+"    bits "+bits+"<br>");
                if(j<16) {    // length of code in bits (0..15)
                       ll[i++] = j;
                } else if(j==16) {    // repeat last length 3 to 6 times 
                       var l;
                    j = 3 + readBits(2);
                    if(i+j > n) {
                        flushBuffer();
                        return 1;
                    }
                    l = i ? ll[i-1] : 0;
                    while(j--) {
                        ll[i++] = l;
                    }
                } else {
                    if(j==17) {        // 3 to 10 zero length codes
                        j = 3 + readBits(3);
                    } else {        // j == 18: 11 to 138 zero length codes 
                        j = 11 + readBits(7);
                    }
                    if(i+j > n) {
                        flushBuffer();
                        return 1;
                    }
                    while(j--) {
                        ll[i++] = 0;
                    }
                }
            }
            /*for(j=0; j<literalCodes+distCodes; j++) {
                //fprintf(errfp, "%d ", ll[j]);
                if ((j&7)==7)
                    fprintf(errfp, "\n");
            }
            fprintf(errfp, "\n");*/
            // Can overwrite tree decode tree as it is not used anymore
            len = literalTree.length;
            for (i=0; i<len; i++)
                literalTree[i]=new HufNode();
            if(CreateTree(literalTree, literalCodes, ll, 0)) {
                flushBuffer();
                return 1;
            }
            len = literalTree.length;
            for (i=0; i<len; i++)
                distanceTree[i]=new HufNode();
            var ll2 = new Array();
            for (i=literalCodes; i <ll.length; i++){
                ll2[i-literalCodes]=ll[i];
            }    
            if(CreateTree(distanceTree, distCodes, ll2, 0)) {
                flushBuffer();
                return 1;
            }
            if (debug)
           		document.write("<br>literalTree");
            while(1) {
                j = DecodeValue(literalTree);
                if(j >= 256) {        // In C64: if carry set
                    var len, dist;
                    j -= 256;
                    if(j == 0) {
                        // EOF
                        break;
                    }
                    j--;
                    len = readBits(cplext[j]) + cplens[j];
    
                    j = DecodeValue(distanceTree);
                    if(cpdext[j] > 8) {
                        dist = readBits(8);
                        dist |= (readBits(cpdext[j]-8)<<8);
                    } else {
                        dist = readBits(cpdext[j]);
                    }
                    dist += cpdist[j];
                    while(len--) {
                        var c = buf32k[(bIdx - dist) & 0x7fff];
                        addBuffer(c);
                    }
                } else {
                    addBuffer(j);
                }
            }
        }
    } while(!last);
    flushBuffer();

    byteAlign();
    return 0;
};

JXG.Util.Unzip.prototype.unzipFile = function(name) {
    var i;
	this.unzip();
	//alert(unzipped[0][1]);
	for (i=0;i<unzipped.length;i++){
		if(unzipped[i][1]==name) {
			return unzipped[i][0];
		}
	}
	
  };
    
    
JXG.Util.Unzip.prototype.unzip = function() {
	//convertToByteArray(input);
	if (debug)
		alert(bA);
	/*for (i=0;i<bA.length*8;i++){
		document.write(readBit());
		if ((i+1)%8==0)
			document.write(" ");
	}*/
	/*for (i=0;i<bA.length;i++){
		document.write(readByte()+" ");
		if ((i+1)%8==0)
			document.write(" ");
	}
	for (i=0;i<bA.length;i++){
		document.write(bA[i]+" ");
		if ((i+1)%16==0)
			document.write("<br>");
	}	
	*/
	//alert(bA);
	nextFile();
	return unzipped;
  };
    
 function nextFile(){
 	if (debug)
 		alert("NEXTFILE");
 	outputArr = [];
 	var tmp = [];
 	modeZIP = false;
	tmp[0] = readByte();
	tmp[1] = readByte();
	if (debug)
		alert("type: "+tmp[0]+" "+tmp[1]);
	if (tmp[0] == parseInt("78",16) && tmp[1] == parseInt("da",16)){ //GZIP
		if (debug)
			alert("GEONExT-GZIP");
		DeflateLoop();
		if (debug)
			alert(outputArr.join(''));
		unzipped[files] = new Array(2);
    	unzipped[files][0] = outputArr.join('');
    	unzipped[files][1] = "geonext.gxt";
    	files++;
	}
	if (tmp[0] == parseInt("1f",16) && tmp[1] == parseInt("8b",16)){ //GZIP
		if (debug)
			alert("GZIP");
		//DeflateLoop();
		skipdir();
		if (debug)
			alert(outputArr.join(''));
		unzipped[files] = new Array(2);
    	unzipped[files][0] = outputArr.join('');
    	unzipped[files][1] = "file";
    	files++;
	}
	if (tmp[0] == parseInt("50",16) && tmp[1] == parseInt("4b",16)){ //ZIP
		modeZIP = true;
		tmp[2] = readByte();
		tmp[3] = readByte();
		if (tmp[2] == parseInt("3",16) && tmp[3] == parseInt("4",16)){
			//MODE_ZIP
			tmp[0] = readByte();
			tmp[1] = readByte();
			if (debug)
				alert("ZIP-Version: "+tmp[1]+" "+tmp[0]/10+"."+tmp[0]%10);
			
			gpflags = readByte();
			gpflags |= (readByte()<<8);
			if (debug)
				alert("gpflags: "+gpflags);
			
			var method = readByte();
			method |= (readByte()<<8);
			if (debug)
				alert("method: "+method);
			
			readByte();
			readByte();
			readByte();
			readByte();
			
			var crc = readByte();
			crc |= (readByte()<<8);
			crc |= (readByte()<<16);
			crc |= (readByte()<<24);
			
			var compSize = readByte();
			compSize |= (readByte()<<8);
			compSize |= (readByte()<<16);
			compSize |= (readByte()<<24);
			
			var size = readByte();
			size |= (readByte()<<8);
			size |= (readByte()<<16);
			size |= (readByte()<<24);
			
			if (debug)
				alert("local CRC: "+crc+"\nlocal Size: "+size+"\nlocal CompSize: "+compSize);
			
			var filelen = readByte();
			filelen |= (readByte()<<8);
			
			var extralen = readByte();
			extralen |= (readByte()<<8);
			
			if (debug)
				alert("filelen "+filelen);
			i = 0;
			nameBuf = [];
			while (filelen--){ 
				var c = readByte();
				if (c == "/" | c ==":"){
					i = 0;
				} else if (i < NAMEMAX-1)
					nameBuf[i++] = String.fromCharCode(c);
			}
			if (debug)
				alert("nameBuf: "+nameBuf);
			
			//nameBuf[i] = "\0";
			if (!fileout)
				fileout = nameBuf;
			
			var i = 0;
			while (i < extralen){
				c = readByte();
				i++;
			}
				
			CRC = 0xffffffff;
			SIZE = 0;
			
			if (size = 0 && fileOut.charAt(fileout.length-1)=="/"){
				//skipdir
				if (debug)
					alert("skipdir");
			}
			if (method == 8){
				DeflateLoop();
				if (debug)
					alert(outputArr.join(''));
				unzipped[files] = new Array(2);
				unzipped[files][0] = outputArr.join('');
    			unzipped[files][1] = nameBuf.join('');
    			files++;
				//return outputArr.join('');
			}
			skipdir();
		}
	}
 };
	
function skipdir(){
    var crc, 
        tmp = [],
        compSize, size, os, i, c;
    
	if ((gpflags & 8)) {
		tmp[0] = readByte();
		tmp[1] = readByte();
		tmp[2] = readByte();
		tmp[3] = readByte();
		
		if (tmp[0] == parseInt("50",16) && 
            tmp[1] == parseInt("4b",16) && 
            tmp[2] == parseInt("07",16) && 
            tmp[3] == parseInt("08",16))
        {
            crc = readByte();
            crc |= (readByte()<<8);
            crc |= (readByte()<<16);
            crc |= (readByte()<<24);
		} else {
			crc = tmp[0] | (tmp[1]<<8) | (tmp[2]<<16) | (tmp[3]<<24);
		}
		
		compSize = readByte();
		compSize |= (readByte()<<8);
		compSize |= (readByte()<<16);
		compSize |= (readByte()<<24);
		
		size = readByte();
		size |= (readByte()<<8);
		size |= (readByte()<<16);
		size |= (readByte()<<24);
		
		if (debug)
			alert("CRC:");
	}

	if (modeZIP)
		nextFile();
	
	tmp[0] = readByte();
	if (tmp[0] != 8) {
		if (debug)
			alert("Unknown compression method!");
        return 0;	
	}
	
	gpflags = readByte();
	if (debug){
		if ((gpflags & ~(parseInt("1f",16))))
			alert("Unknown flags set!");
	}
	
	readByte();
	readByte();
	readByte();
	readByte();
	
	readByte();
	os = readByte();
	
	if ((gpflags & 4)){
		tmp[0] = readByte();
		tmp[2] = readByte();
		len = tmp[0] + 256*tmp[1];
		if (debug)
			alert("Extra field size: "+len);
		for (i=0;i<len;i++)
			readByte();
	}
	
	if ((gpflags & 8)){
		i=0;
		nameBuf=[];
		while (c=readByte()){
			if(c == "7" || c == ":")
				i=0;
			if (i<NAMEMAX-1)
				nameBuf[i++] = c;
		}
		//nameBuf[i] = "\0";
		if (debug)
			alert("original file name: "+nameBuf);
	}
		
	if ((gpflags & 16)){
		while (c=readByte()){
			//FILE COMMENT
		}
	}
	
	if ((gpflags & 2)){
		readByte();
		readByte();
	}
	
	DeflateLoop();
	
	crc = readByte();
	crc |= (readByte()<<8);
	crc |= (readByte()<<16);
	crc |= (readByte()<<24);
	
	size = readByte();
	size |= (readByte()<<8);
	size |= (readByte()<<16);
	size |= (readByte()<<24);
	
	if (modeZIP)
		nextFile();
	
};

};

/**
*  Base64 encoding / decoding
*  @see <a href="http://www.webtoolkit.info/">http://www.webtoolkit.info/</A>
*/
JXG.Util.Base64 = {

    // private property
    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

    // public method for encoding
    encode : function (input) {
        var output = [],
            chr1, chr2, chr3, enc1, enc2, enc3, enc4,
            i = 0;

        input = JXG.Util.Base64._utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output.push([this._keyStr.charAt(enc1),
                         this._keyStr.charAt(enc2),
                         this._keyStr.charAt(enc3),
                         this._keyStr.charAt(enc4)].join(''));
        }

        return output.join('');
    },

    // public method for decoding
    decode : function (input, utf8) {
        var output = [],
            chr1, chr2, chr3,
            enc1, enc2, enc3, enc4,
            i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output.push(String.fromCharCode(chr1));

            if (enc3 != 64) {
                output.push(String.fromCharCode(chr2));
            }
            if (enc4 != 64) {
                output.push(String.fromCharCode(chr3));
            }
        }
        
        output = output.join(''); 
        
        if (utf8) {
            output = JXG.Util.Base64._utf8_decode(output);
        }
        return output;

    },

    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // private method for UTF-8 decoding
    _utf8_decode : function (utftext) {
        var string = [],
            i = 0,
            c = 0, c2 = 0, c3 = 0;

        while ( i < utftext.length ) {
            c = utftext.charCodeAt(i);
            if (c < 128) {
                string.push(String.fromCharCode(c));
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
                i += 3;
            }
        }
        return string.join('');
    },
    
    _destrip: function (stripped, wrap){
        var lines = [], lineno, i,
            destripped = [];
        
        if (wrap==null) 
            wrap = 76;
            
        stripped.replace(/ /g, "");
        lineno = stripped.length / wrap;
        for (i = 0; i < lineno; i++)
            lines[i]=stripped.substr(i * wrap, wrap);
        if (lineno != stripped.length / wrap)
            lines[lines.length]=stripped.substr(lineno * wrap, stripped.length-(lineno * wrap));
            
        for (i = 0; i < lines.length; i++)
            destripped.push(lines[i]);
        return destripped.join('\n');
    },
    
    decodeAsArray: function (input){
        var dec = this.decode(input),
            ar = [], i;
        for (i=0;i<dec.length;i++){
            ar[i]=dec.charCodeAt(i);
        }
        return ar;
    },
    
    decodeGEONExT : function (input) {
        return decodeAsArray(destrip(input),false);
    }
};

/**
 * @private
 */
JXG.Util.asciiCharCodeAt = function(str,i){
	var c = str.charCodeAt(i);
	if (c>255){
    	switch (c) {
			case 8364: c=128;
	    	break;
	    	case 8218: c=130;
	    	break;
	    	case 402: c=131;
	    	break;
	    	case 8222: c=132;
	    	break;
	    	case 8230: c=133;
	    	break;
	    	case 8224: c=134;
	    	break;
	    	case 8225: c=135;
	    	break;
	    	case 710: c=136;
	    	break;
	    	case 8240: c=137;
	    	break;
	    	case 352: c=138;
	    	break;
	    	case 8249: c=139;
	    	break;
	    	case 338: c=140;
	    	break;
	    	case 381: c=142;
	    	break;
	    	case 8216: c=145;
	    	break;
	    	case 8217: c=146;
	    	break;
	    	case 8220: c=147;
	    	break;
	    	case 8221: c=148;
	    	break;
	    	case 8226: c=149;
	    	break;
	    	case 8211: c=150;
	    	break;
	    	case 8212: c=151;
	    	break;
	    	case 732: c=152;
	    	break;
	    	case 8482: c=153;
	    	break;
	    	case 353: c=154;
	    	break;
	    	case 8250: c=155;
	    	break;
	    	case 339: c=156;
	    	break;
	    	case 382: c=158;
	    	break;
	    	case 376: c=159;
	    	break;
	    	default:
	    	break;
	    }
	}
	return c;
};

/**
 * Decoding string into utf-8
 * @param {String} string to decode
 * @return {String} utf8 decoded string
 */
JXG.Util.utf8Decode = function(utftext) {
  var string = [];
  var i = 0;
  var c = 0, c1 = 0, c2 = 0, c3;
  if (!JXG.exists(utftext)) return '';
  
  while ( i < utftext.length ) {
    c = utftext.charCodeAt(i);

    if (c < 128) {
      string.push(String.fromCharCode(c));
      i++;
    } else if((c > 191) && (c < 224)) {
      c2 = utftext.charCodeAt(i+1);
      string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
      i += 2;
    } else {
      c2 = utftext.charCodeAt(i+1);
      c3 = utftext.charCodeAt(i+2);
      string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
      i += 3;
    }
  };
  return string.join('');
};

/**
 * Generate a random uuid.
 * http://www.broofa.com
 * mailto:robert@broofa.com
 *
 * Copyright (c) 2010 Robert Kieffer
 * Dual licensed under the MIT and GPL licenses.
 *
 * EXAMPLES:
 *   >>> Math.uuid()
 *   "92329D39-6F5C-4520-ABFC-AAB64544E172"
 */
JXG.Util.genUUID = function() {
    // Private array of chars to use
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
        uuid = new Array(36), rnd=0, r;

    for (var i = 0; i < 36; i++) {
      if (i==8 || i==13 ||  i==18 || i==23) {
        uuid[i] = '-';
      } else if (i==14) {
        uuid[i] = '4';
      } else {
        if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
        r = rnd & 0xf;
        rnd = rnd >> 4;
        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
      }
    }

    return uuid.join('');
};


/*
    Copyright 2009.2010
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

JXG.PsTricks = {

    convert: function (board) {
        var topleft = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0, 0], board),
            bottomright = new JXG.Coords(JXG.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board),
            i, el, result = [];

        result.push('\\begin{pspicture*}('+topleft.usrCoords[1]+','+bottomright.usrCoords[2]+')('+bottomright.usrCoords[1]+','+topleft.usrCoords[2]+')\n');

        for(i in board.objects) {
            el = board.objects[i];

            if (el.visProp.visible) {
                switch (el.elementClass) {
                    case JXG.OBJECT_CLASS_CIRCLE:
                        result.push(this.addCircle(el));
                        break;
                    case JXG.OBJECT_CLASS_LINE:
                        result.push(this.addLine(el));
                        break;
                    case JXG.OBJECT_CLASS_POINT:
                        result.push(this.addPoint(el));
                        break;
                    default:
                        switch (el.type) {
                            case JXG.OBJECT_TYPE_ARC:
                                result.push(this.addArc(el));
                                break;
                            case JXG.OBJECT_TYPE_SECTOR:
                                result.push(this.addArc(el));
                                result.push(this.addSector(el));
                                break;
                            case JXG.OBJECT_TYPE_POLYGON:
                                result.push(this.addPolygon(el));
                                break;
                            case JXG.OBJECT_TYPE_ANGLE:
                                result.push(this.addAngle(el));
                                break;
                        }
                        break;
                }
            }
        }

        result.push('\\end{pspicture*}');

        return result.join('\n');
    },

    setArrows: function (el) {
        var result = '';

        if(el.visProp.firstarrow && el.visProp.lastarrow) {
            result = '{<->}';
        } else if (el.visProp.firstarrow) {
            result = '{<-}';
        } else if (el.visProp.lastarrow) {
            result = '{->}';
        }

        return result;
    },

    /**
     * Draws a wedge.
     * @param {String} color HTML/CSS color string.
     * @param {Number} opacity Numbe between 0 and 1.
     * @param {Array} midpoint x and y value of the midpoint.
     * @param {Number} radius
     * @param {Number} angle1
     * @param {Number} angle2
     */
    drawWedge: function (color, opacity, midpoint, radius, angle1, angle2) {
        var result = '';

        if(color != 'none' && opacity > 0) {
            result += "\\pswedge[linestyle=none, fillstyle=solid, fillcolor="+this.parseColor(color)+", opacity="+opacity.toFixed(5)+"]";
            result += "("+midpoint.join(',')+"){"+radius+"}{"+angle1+"}{"+angle2+"}\n";
        }

        return result;
    },

    addPoint: function (el) {
        var result = "\\psdot[linecolor=" + this.parseColor(el.visProp.strokecolor) + ",dotstyle=",
            face = el.normalizeFace(el.visProp.face) || 'o',
            size = el.visProp.size > 4 ? 4 : el.visProp.size,
            sizemap = [0, 0, '2pt 2', '5pt 2', '5pt 3'];

        // TODO: size == 1 and size > 4, faces <>, ^, v, <, and >

        if(face == 'x') {
            result += "x, dotsize=" + sizemap[size];
        } else if(face == 'o') {
            result += "*, dotsize=";
            if(size == 1) {
                result += "2pt 2";
            } else if(size == 2) {
                result += "4pt 2";
            } else if(size == 3) {
                result += "6pt 2";
            } else if(size == 4) {
                result += "6pt 3";
            }
        } else if(face == '[]') {
            result += "square*, dotsize=" + sizemap[size];
        } else if(face == '+') {
            result += "+, dotsize=" + sizemap[size];
        }
        result += "]("+el.coords.usrCoords.slice(1).join(',')+")\n";
        result += "\\rput("+(el.coords.usrCoords[1]+15/ el.board.unitY)+","+(el.coords.usrCoords[2]+15/ el.board.unitY)+"){\\small $"+el.name+"$}\n";

        return result;
    },

    addLine: function (el) {
        var screenCoords1 = new JXG.Coords(JXG.COORDS_BY_USER, el.point1.coords.usrCoords, el.board),
            screenCoords2 = new JXG.Coords(JXG.COORDS_BY_USER, el.point2.coords.usrCoords, el.board),
            result = "\\psline[linecolor=" + this.parseColor(el.visProp.strokecolor) + ", linewidth=" +el.visProp.strokewidth+"px]";

        if(el.visProp.straightfirst || el.visProp.straightlast) {
            JXG.Math.Geometry.calcStraight(el, screenCoords1, screenCoords2);
        }

        result += this.setArrows(el);
        result += "("+screenCoords1.usrCoords.slice(1).join(',')+")("+screenCoords2.usrCoords.slice(2).join(',')+")\n";

        return result;
    },

    addCircle: function (el) {
        var radius = el.Radius(),
            result = "\\pscircle[linecolor=" + this.parseColor(el.visProp.strokecolor) +", linewidth=" +el.visProp.strokewidth+"px";

        if(el.visProp.fillcolor != 'none' && el.visProp.fillopacity != 0) {
            result += ", fillstyle=solid, fillcolor="+this.parseColor(el.visProp.fillcolor)+", opacity="+el.visProp.fillopacity.toFixed(5);
        }
        result += "]("+el.center.coords.usrCoords.slice(1).join('1')+"){"+radius+"}\n";

        return result;
    },

    addPolygon: function (el) {
        var result = "\\pspolygon[linestyle=none, fillstyle=solid, fillcolor="+this.parseColor(el.visProp.fillcolor)+", opacity="+el.visProp.fillopacity.toFixed(5)+"]",
            i;

        for(i = 0; i < el.vertices.length; i++) {
            result += "("+el.vertices[i].coords.usrCoords.slice(1).join(',')+")";
        }
        result += "\n";

        return result;
    },

    addArc: function (el) {
        var radius = el.Radius(),
            p = {
                coords: new JXG.Coords(JXG.COORDS_BY_USER,[el.board.canvasWidth/(el.board.unitY), el.center.coords.usrCoords[2]], el.board)
            },
            angle2 = JXG.Math.Geometry.trueAngle(p, el.center, el.point2).toFixed(4),
            angle1 = JXG.Math.Geometry.trueAngle(p, el.center, el.point3).toFixed(4),
            result = "\\psarc[linecolor=" + this.parseColor(el.visProp.strokecolor) + ", linewidth=" +el.visProp.strokewidth+"px]";

        result += this.setArrows(el);
        result += "("+el.center.coords.usrCoords.slice(1).join(',')+"){"+radius+"}{"+angle2+"}{"+angle1+"}\n";

        return result;
    },

    addSector: function (el) {
        var radius = el.Radius(),
            p = {
                coords: new JXG.Coords(JXG.COORDS_BY_USER, [el.board.canvasWidth / (el.board.unitY), el.point1.coords.usrCoords[2]], el.board)
            },
            angle2 = JXG.Math.Geometry.trueAngle(p, el.point1, el.point2).toFixed(4),
            angle1 = JXG.Math.Geometry.trueAngle(p, el.point1, el.point3).toFixed(4);

        return this.drawWedge(el.visProp.fillcolor, el.visProp.fillopacity, el.point1.coords.usrCoords.slice(1), radius, angle2, angle1);
    },

    addAngle: function (el) {
        var radius = el.radius,
            p = {
                coords: new JXG.Coords(JXG.COORDS_BY_USER, [el.board.canvasWidth/(el.board.unitY), el.point2.coords.usrCoords[2]], el.board)
            },
            angle2 = JXG.Math.Geometry.trueAngle(p, el.point2, el.point1).toFixed(4),
            angle1 = JXG.Math.Geometry.trueAngle(p, el.point2, el.point3).toFixed(4),
            result;

        result = this.drawWedge(el.visProp.fillcolor, el.visProp.fillopacity, el.point2.coords.usrCoords.slice(1), radius, angle2, angle1);

        result += "\\psarc[linecolor=" + this.parseColor(el.visProp.strokecolor) + ", linewidth=" +el.visProp.strokewidth+"px]";
        result += "("+el.point2.coords.usrCoords.slice(1).join(',')+"){"+radius+"}{"+angle2+"}{"+angle1+"}\n";

        return result;
    },

    parseColor: function (color) {
        var arr = JXG.rgbParser(color);
        return "{[rgb]{"+arr[0]/255+","+arr[1]/255+","+arr[2]/255+"}}";
    }
};

/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
*/

/** 
 * @fileoverview The JXG.Server is a wrapper for a smoother integration of server side calculations. on the
 * server side a python plugin system is used.
 */

/**
 * @namespace
 * JXG.Server namespace holding functions to load JXG server modules.
 */
JXG.Server = function(){};

/**
 * This is where all of a module's handlers are accessed from. If you're loading a module named JXGModule which
 * provides a handler called ImaHandler, then this handler can be called by invoking JXG.Server.modules.JXGModule.ImaHandler().
 * @namespace
 */
JXG.Server.modules = function(){};

/**
 * Stores all asynchronous calls to server which aren't finished yet.
 * @private
 */
JXG.Server.runningCalls = {};

/**
 * Handles errors, just a default implementation, can be overwritten by you, if you want to handle errors by yourself.
 * @param {object} data An object holding a field of type string named message handling the error described in the message string.
 */
JXG.Server.handleError = function(data) {
	alert('error occured, server says: ' + data.message);
};

/**
 * The main method of JXG.Server. Actually makes the calls to the server and parses the feedback.
 * @param {string} action Can be 'load' or 'exec'.
 * @param {function} callback Function pointer or anonymous function which takes as it's only argument an
 * object containing the data from the server. The fields of this object depend on the reply of the server
 * module. See the correspondings server module readme.
 * @param {object} data What is to be sent to the server.
 * @param {boolean} sync If the call should be synchronous or not.
 */
JXG.Server.callServer = function(action, callback, data, sync) {
	var fileurl, passdata, AJAX,
	params, id, dataJSONStr,
	k;

    sync = sync || false;

	params = '';
	for(k in data) {
		params += '&' + escape(k) + '=' + escape(data[k]);
	}

	dataJSONStr = JXG.toJSON(data);

	// generate id
	do {
		id = action + Math.floor(Math.random()*4096);
	} while(typeof this.runningCalls[id] != 'undefined');

	// store information about the calls
	this.runningCalls[id] = {action: action};
	if(typeof data.module != 'undefined')
		this.runningCalls[id].module = data.module;

	fileurl = JXG.serverBase + 'JXGServer.py';
    passdata = 'action=' + escape(action) + '&id=' + id + '&dataJSON=' + escape(JXG.Util.Base64.encode(dataJSONStr));

	this.cbp = function(d) {
		var str, data,
		tmp, inject, paramlist, id,
		i, j;

		str = (new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(d))).unzip();
		if(JXG.isArray(str) && str.length > 0)
			str = str[0][0];

        if(typeof str != 'string')
            return;

        data = window.JSON && window.JSON.parse ? window.JSON.parse(str) : (new Function('return ' + str))();
		//data = eval("(" + str + ")");

		if(data.type == 'error') {
			this.handleError(data);
		} else if (data.type == 'response') {
			id = data.id;

			// inject fields
			for(i=0; i<data.fields.length; i++) {
				tmp = data.fields[i];
				//inject = tmp.namespace + ( typeof eval(tmp.namespace) == 'object' ? '.' : '.prototype.') + tmp.name + ' = ' + tmp.value;
                inject = tmp.namespace + ( typeof ((new Function('return ' + tmp.namespace))()) == 'object' ? '.' : '.prototype.') + tmp.name + ' = ' + tmp.value;
				//eval(inject);
                (new Function(inject))();
			}

			// inject handlers
			for(i=0; i<data.handler.length; i++) {
				tmp = data.handler[i];
				paramlist = [];

				for(j=0; j<tmp.parameters.length; j++) {
					paramlist[j] = '"' + tmp.parameters[j] + '": ' + tmp.parameters[j];
				}
				// insert subnamespace named after module.
				inject = 'if(typeof JXG.Server.modules.' + this.runningCalls[id].module + ' == "undefined")' +
				'JXG.Server.modules.' + this.runningCalls[id].module + ' = {};';

				// insert callback method which fetches and uses the server's data for calculation in JavaScript
				inject += 'JXG.Server.modules.' + this.runningCalls[id].module + '.' + tmp.name + '_cb = ' + tmp.callback + ';';

				// insert handler as JXG.Server.modules.<module name>.<handler name>
				inject += 'JXG.Server.modules.' + this.runningCalls[id].module + '.' + tmp.name + ' = function (' + tmp.parameters.join(',') + ', __JXGSERVER_CB__, __JXGSERVER_SYNC) {' +
				'if(typeof __JXGSERVER_CB__ == "undefined") __JXGSERVER_CB__ = JXG.Server.modules.' + this.runningCalls[id].module + '.' + tmp.name + '_cb;' +
				'var __JXGSERVER_PAR__ = {' + paramlist.join(',') + ', "module": "' + this.runningCalls[id].module + '", "handler": "' + tmp.name + '" };' +
				'JXG.Server.callServer("exec", __JXGSERVER_CB__, __JXGSERVER_PAR__, __JXGSERVER_SYNC);' +
				'};';
				//eval(inject);
                (new Function(inject))();
			}

			delete this.runningCalls[id];

			// handle data
			callback(data.data);
		}
	};

	// bind cbp callback method to JXG.Server to get access to JXG.Server fields from within cpb
	this.cb = JXG.bind(this.cbp, this);

    // we're using our own XMLHttpRequest object in here because of a/sync and POST
    if (window.XMLHttpRequest) {
        AJAX = new XMLHttpRequest();
        AJAX.overrideMimeType('text/plain; charset=iso-8859-1');
    } else {                                  
        AJAX = new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (AJAX) {
        // POST is required if data sent to server is too long for a url.
        // some browsers/http servers don't accept long urls.
        AJAX.open("POST", fileurl, !sync);
        AJAX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

        if(!sync) {
            // Define function to fetch data received from server
            // that function returning a function is required to make this.cb known to the function.
            AJAX.onreadystatechange = (function(cb){ return function () {
                switch(AJAX.readyState) {
                    // server is ready for take-off
                    case 4:
                        if(AJAX.status != 200) { }
                            //alert("Fehler:" + AJAX.status);
                        else  { // grab it and call the server callback to debase64, unzip, and parse the data
                            cb(AJAX.responseText);
                        }
                    break;
                    default:
                        return false;
                    break;
                }
            }})(this.cb);
        }

        // send the data
        AJAX.send(passdata);
        if(sync)
            this.cb(AJAX.responseText);
    } else {
        return false;
    }

//	JXG.FileReader.parseFileContent(fileurl, this.cb, 'raw', !sync);
};

/**
 * Callback for the default action 'load'.
 */
JXG.Server.loadModule_cb = function(data) {
	var i;
	for(i=0; i<data.length; i++)
		alert(data[i].name + ': ' + data[i].value);
};

/**
 * Loads a module from the server.
 * @param {string} module A string containing the module. Has to match the filename of the Python module on the server exactly including
 * lower and upper case letters without the file ending .py.
 */
JXG.Server.loadModule = function(module) {
	return JXG.Server.callServer('load', JXG.Server.loadModule_cb, {'module': module}, true);
};

JXG.Server.load = JXG.Server.loadModule;



/*
    Copyright 2008,2009
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph. If not, see <http://www.gnu.org/licenses/>.
*/

/** 
 * @fileoverview The JXG.DataSource is a helper class for data organization. Currently supported data sources are
 * javascript arrays and HTML tables.
 */

/* NOT YET DOCUMENTED. TODO! */

JXG.DataSource = function() {

    this.data = [];
    this.columnHeaders = [];
    this.rowHeaders = [];

    return this;
};

JXG.extend(JXG.DataSource.prototype, /** @lends JXG.DataSource.prototype */ {
    loadFromArray: function(table, columnHeader, rowHeader) {
        var i, j,cell;

        if(typeof columnHeader == 'undefined')
            columnHeader = false;
        if(typeof rowHeader == 'undefined')
            rowHeader = false;

        if(JXG.isArray(columnHeader)) {
            this.columnHeaders = columnHeader;
            columnHeader = false;
        }

        if(JXG.isArray(rowHeader)) {
            this.rowHeaders = rowHeader;
            rowHeader = false;
        }

        this.data = [];
        if(columnHeader)
            this.columnHeaders = [];
        if(rowHeader)
            this.rowHeaders = [];

        if(typeof table != 'undefined') {
            // extract the data
            this.data = new Array(table.length);

            for(i=0; i<table.length; i++) {
                this.data[i] = new Array(table[i].length);
                for(j=0; j<table[i].length; j++) {
                    cell = table[i][j];
                    if('' + parseFloat(cell) == cell)
                        this.data[i][j] = parseFloat(cell);
                    else if (cell != '-')
                        this.data[i][j] = cell;
                    else
                        this.data[i][j] = NaN;
                }
            }
                
            if(columnHeader) {
                this.columnHeaders = this.data[0].slice(1);
                this.data = this.data.slice(1);
            }

            if(rowHeader) {
                this.rowHeaders = new Array();
                for(i=0; i<this.data.length; i++) {
                    this.rowHeaders.push(this.data[i][0]);
                    this.data[i] = this.data[i].slice(1);
                }
            }
        }

        return this;
    },

    loadFromTable: function(table, columnHeader, rowHeader) {
        var row, i, j, col, cell, name;

        if(typeof columnHeader == 'undefined')
            columnHeader = false;
        if(typeof rowHeader == 'undefined')
            rowHeader = false;

        if(JXG.isArray(columnHeader)) {
            this.columnHeaders = columnHeader;
            columnHeader = false;
        }

        if(JXG.isArray(rowHeader)) {
            this.rowHeaders = rowHeader;
            rowHeader = false;
        }

        this.data = [];
        if(columnHeader)
            this.columnHeaders = [];
        if(rowHeader)
            this.rowHeaders = [];

        // todo: the user should provide the dom node directly
        // to adjust: examples in examples folder & wiki
        table = document.getElementById(table);

        if(typeof table != 'undefined') {
            // extract the data
            row = table.getElementsByTagName('tr');
            this.data = new Array(row.length);

            for(i=0; i<row.length; i++) {
                col = row[i].getElementsByTagName('td');
                this.data[i] = new Array(col.length);
                for(j=0; j<col.length; j++) {
                    cell = col[j].innerHTML;
                    if('' + parseFloat(cell) == cell)
                        this.data[i][j] = parseFloat(cell);
                    else if (cell != '-')
                        this.data[i][j] = cell;
                    else
                        this.data[i][j] = NaN;
                }
            }
                
            if(columnHeader) {
                this.columnHeaders = this.data[0].slice(1);
                this.data = this.data.slice(1);
            }

            if(rowHeader) {
                this.rowHeaders = new Array();
                for(i=0; i<this.data.length; i++) {
                    this.rowHeaders.push(this.data[i][0]);
                    this.data[i] = this.data[i].slice(1);
                }
            }
        }

        return this;
    },

    addColumn: function(name, pos, data) {
        // todo
    },

    addRow: function(name, pos, data) {
        // todo
    },

    getColumn: function(col) {
        var result = new Array(this.data.length), i;

        // get column index if column is given as column header title
        if(typeof col == 'string') {
            for(i=0; i<this.columnHeaders.length; i++) {
                if(col == this.columnHeaders[i]) {
                    col = i;
                    break;
                }
            }
        }

        // build column array
        for(i=0; i<this.data.length; i++) {
            if(this.data[i].length > col)
                result[i] = parseFloat(this.data[i][col]);
        }

        return result;
    },

    getRow: function(row) {
        var result, i;

        // get column index if column is given as column header title
        if(typeof row == 'string') {
            for(i=0; i<this.rowHeaders.length; i++) {
                if(row == this.rowHeaders[i]) {
                    row = i;
                    break;
                }
            }
        }

        // allocate memory for result array
        result = new Array(this.data[row].length);

        // build column array. result = this.data[row] is a flat copy and will
        // destroy our local data copy, that's why we're copying it element wise.
        for(i=0; i<this.data[row].length; i++) {
            result[i] = this.data[row][i];
        }

        return result;
    }
});


/*
    JessieCode Parser and Compiler

    Copyright 2011-2012
        Michael Gerhäuser
        Alfred Wassermann

    Licensed under the LGPL v3
*/

/**
 * @fileoverview JessieCode is a scripting language designed to provide a simple scripting language to build constructions
 * with JSXGraph. It is similar to JavaScript, but prevents access to the DOM. Hence, it can be used in community driven
 * Math portals which want to use JSXGraph to display interactive math graphics.
 */

/**
 * A JessieCode object provides an interfacce to the parser and stores all variables and objects used within a JessieCode script.
 * The optional argument <tt>code</tt> is interpreted after initializing. To evaluate more code after initializing a JessieCode instance
 * please use {@link JXG.JessieCode#parse}. For code snippets like single expressions use {@link JXG.JessieCode#snippet}.
 * @constructor
 * @param {String} [code] Code to parse.
 * @param {Boolean} [geonext=false] Geonext compatibility mode.
 */
JXG.JessieCode = function(code, geonext) {
    var i;

    // Control structures

    /**
     * Stores all variables, local and global. The current scope is determined by {@link JXG.JessieCode#scope}.
     * @type Array
     * @private
     */
    this.sstack = [{}];

    /**
     * Defines the current variable scope.
     * @type Number
     * @private
     */
    this.scope = 0;

    /**
     * A stack used to store the parameter lists for function definitions and calls.
     * @type Array
     * @private
     */
    this.pstack = [[]];

    /**
     * A stack to store debug information (like line and column where it was defined) of a parameter
     * @type Array
     * @private
     */
    this.dpstack = [[]];

    /**
     * Determines the parameter stack scope.
     * @type Number
     * @private
     */
    this.pscope = 0;

    /**
     * Used to store the property-value definition while parsing an object literal.
     * @type Array
     * @private
     */
    this.propstack = [{}];

    /**
     * The current scope of the object literal stack {@link JXG.JessieCode#propstack}.
     * @type Number
     * @private
     */
    this.propscope = 0;

    /**
     * Whenever an element attribute is set via <tt>element.attribute = 'something';</tt>, the element is stored
     * in here, so following attribute changes can be set without the element: <tt>.attribute = 'something else';</tt>.
     * @type JXG.GeometryElement
     * @private
     */
    this.propobj = 0;

    /**
     * Store the left hand side of an assignment. If an element is constructed and no attributes are given, this is
     * used as the element's name.
     * @type Array
     * @private
     */
    this.lhs = [];

    /**
     * lhs flag, used by JXG.JessieCode#replaceNames
     * @type Boolean
     * @default false
     */
    this.isLHS = false;

    /**
     * The id of an HTML node in which innerHTML all warnings are stored (if no <tt>console</tt> object is available).
     * @type String
     * @default 'jcwarn'
     */
    this.warnLog = 'jcwarn';

    /**
     * Built-in functions and constants
     * @type Object
     */
    this.builtIn = this.defineBuiltIn();

    /**
     * The board which currently is used to create and look up elements.
     * @type JXG.Board
     */
    this.board = null;

    /**
     * Keep track of which element is created in which line.
     * @type Object
     */
    this.lineToElement = {};

    this.countLines = true;
    this.parCurLine = 1;
    this.parCurColumn = 0;
    this.line = 1;
    this.col = 1;
    
    this.code = '';

    if (typeof code === 'string') {
        this.parse(code);
    }
};


JXG.extend(JXG.JessieCode.prototype, /** @lends JXG.JessieCode.prototype */ {
    /**
     * Create a new parse tree node.
     * @param {String} type Type of node, e.g. node_op, node_var, or node_const
     * @param value The nodes value, e.g. a variables value or a functions body.
     * @param {Array} children Arbitrary number of child nodes.
     */
    node: function (type, value, children) {
        return {
            type: type,
            value: value,
            children: children
        };
    },

    /**
     * Create a new parse tree node. Basically the same as node(), but this builds
     * the children part out of an arbitrary number of parameters, instead of one
     * array parameter.
     * @param {String} type Type of node, e.g. node_op, node_var, or node_const
     * @param value The nodes value, e.g. a variables value or a functions body.
     * @param children Arbitrary number of parameters; define the child nodes.
     */
    createNode: function (type, value, children) {
        var n = this.node(type, value, []),
            i;

        for(i = 2; i < arguments.length; i++)
            n.children.push( arguments[i] );

        n.line = this.parCurLine;
        n.col = this.parCurColumn;

        return n;
    },

    /**
     * Looks up an {@link JXG.GeometryElement} by its id.
     * @param {String} id
     * @returns {JXG.GeometryElement}
     */
    getElementById: function (id) {
        return this.board.objects[id];
    },

    /**
     * Returns a element creator function which takes two parameters: the parents array and the attributes object.
     * @param {String} vname The element type, e.g. 'point', 'line', 'midpoint'
     * @returns {function}
     */
    creator: (function () {
        // stores the already defined creators
        var _ccache = {}, r;

        r = function (vname) {
            var f;

            // _ccache is global, i.e. it is the same for ALL JessieCode instances.
            // That's why we need the board id here
            if (typeof _ccache[this.board.id + vname] === 'function') {
                return _ccache[this.board.id + vname];
            } else {
                f = (function (that) {
                    return function (parameters, attributes) {
                        var attr;

                        if (JXG.exists(attributes)) {
                            attr = attributes;
                        } else {
                            attr = {name: (that.lhs[that.scope] !== 0 ? that.lhs[that.scope] : '')};
                        }
                        return that.board.create(vname, parameters, attr);
                    }
                })(this);

                f.creator = true;
                _ccache[this.board.id + vname] = f;

                return f;
            }

        };

        r.clearCache = function () {
            _ccache = {};
        };

        return r;
    })(),

    /**
     * Assigns a value to a variable in the current scope.
     * @param {String} vname Variable name
     * @param {%} value Anything
     * @see JXG.JessieCode#sstack
     * @see JXG.JessieCode#scope
     */
    letvar: function (vname, value) {
        if (this.builtIn[vname]) {
            this._warn('"' + vname + '" is a predefined value.');
        }

        this.sstack[this.scope][vname] = value;
    },

    /**
     * Checks if the given variable name can be found in {@link JXG.JessieCode#sstack}.
     * @param {String} vname
     * @returns {Number} The position in the local variable stack where the variable can be found. <tt>-1</tt> if it couldn't be found.
     */
    isLocalVariable: function (vname) {
        var s;
        for (s = this.scope; s > -1; s--) {
            if (JXG.exists(this.sstack[s][vname])) {
                return s;
            }
        }

        return -1;
    },

    /**
     * Checks if the given variable name is a valid creator method.
     * @param {String} vname
     * @returns {Boolean}
     */
    isCreator: function (vname) {
        // check for an element with this name
        return !!JXG.JSXGraph.elements[vname];
    },

    /**
     * Checks if the given variable identifier is a valid member of the JavaScript Math Object.
     * @param {String} vname
     * @returns {Boolean}
     */
    isMathMethod: function (vname) {
        return vname !== 'E' && !!Math[vname];
    },

    /**
     * Returns true if the given identifier is a builtIn variable/function.
     * @param {String} vname
     * @returns {Boolean}
     */
    isBuiltIn: function (vname) {
        return !!this.builtIn[vname];
    },

    /**
     * Looks up the value of the given variable.
     * @param {String} vname Name of the variable
     * @paran {Boolean} [local=false] Only look up the internal symbol table and don't look for
     * the <tt>vname</tt> in Math or the element list.
     */
    getvar: function (vname, local) {
        var s, undef;

        local = JXG.def(local, false);

        s = this.isLocalVariable(vname);
        if (s > -1) {
            return this.sstack[s][vname];
        }

        // check for an element with this name
        if (this.isCreator(vname)) {
            return this.creator(vname);
        }

        if (this.isMathMethod(vname)) {
            return Math[vname];
        }

        if (this.isBuiltIn(vname)) {
            return this.builtIn[vname];
        }

        if (!local) {
            s = JXG.getRef(this.board, vname);
            if (s !== vname) {
                return s;
            }
        }

        return undef;
    },

    /**
     * Looks up a variable identifier in various tables and generates JavaScript code that could be eval'd to get the value.
     * @param {String} vname Identifier
     * @param {Boolean} [local=false] Don't resolve ids and names of elements
     */
    getvarJS: function (vname, local, withProps) {
        var s;

        local = JXG.def(local, false);
        withProps = JXG.def(withProps, false);

        if (JXG.indexOf(this.pstack[this.pscope], vname) > -1) {
            return vname;
        }

        s = this.isLocalVariable(vname);
        if (s > -1 && !withProps) {
            return '$jc$.sstack[' + s + '][\'' + vname + '\']';
        }

        // check for an element with this name
        if (this.isCreator(vname)) {
            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])); })';
        }
        
        if (withProps) {
            this._error('Syntax error (attribute values are allowed with element creators only)');
        }

        if (this.isMathMethod(vname)) {
            return 'Math.' + vname;
        }

        if (this.isBuiltIn(vname)) {
            // if src does not exist, it is a number. in that case, just return the value.
            return this.builtIn[vname].src || this.builtIn[vname];
        }

        if (!local) {
            if (JXG.isId(this.board, vname)) {
                return '$jc$.board.objects[\'' + vname + '\']';
            } else if (JXG.isName(this.board, vname)) {
                return '$jc$.board.elementsByName[\'' + vname + '\']';
            } else if (JXG.isGroup(this.board, vname)) {
                return '$jc$.board.groups[\'' + vname + '\']';
            }
            //return 'JXG.getRef(JXG.JSXGraph.boards[$jc$.board.id], \'' + vname + '\')';
        }

        return '';
    },

    /**
     * Merge all atribute values given with an element creator into one object.
     * @param {Object} ... An arbitrary number of objects
     * @returns {Object} All given objects merged into one. If properties appear in more (case sensitive) than one
     * object the last value is taken.
     */
    mergeAttributes: function () {
        var i, attr = {};
        
        for (i = 0; i < arguments.length; i++) {
            attr = JXG.deepCopy(attr, arguments[i], true);            
        }
        
        return attr;
    },

    /**
     * Sets the property <tt>what</tt> of {@link JXG.JessieCode#propobj} to <tt>value</tt>
     * @param {String} what
     * @param {%} value
     */
    setProp: function (o, what, value) {
        var par = {}, x, y;

        if (o.elementClass === JXG.OBJECT_CLASS_POINT && (what === 'X' || what === 'Y')) {
            // set coords

            what = what.toLowerCase();

            // be advised, we've spotted three cases in your AO:
            // o.isDraggable && typeof value === number:
            //   stay draggable, just set the new coords (e.g. via moveTo)
            // o.isDraggable && typeof value === function:
            //   convert to !o.isDraggable, set the new coords via o.addConstraint()
            // !o.isDraggable:
            //   stay !o.isDraggable, update the given coord by overwriting X/YEval

            if (o.isDraggable && typeof value === 'number') {
                x = what === 'x' ? value : o.X();
                y = what === 'y' ? value : o.Y();

                o.setPosition(JXG.COORDS_BY_USER, [x, y]);
            } else if (o.isDraggable && (typeof value === 'function' || typeof value === 'string')) {
                x = what === 'x' ? value : o.coords.usrCoords[1];
                y = what === 'y' ? value : o.coords.usrCoords[2];

                o.addConstraint([x, y]);
            } else if (!o.isDraggable) {
                x = what === 'x' ? value : o.XEval.origin;
                y = what === 'y' ? value : o.YEval.origin;

                o.addConstraint([x, y]);
            }

            this.board.update();
        } else if (o.type === JXG.OBJECT_TYPE_TEXT && (what === 'X' || what === 'Y')) {
            if (typeof value === 'number') {
                o[what] = function () { return value; };
            } else if (typeof value === 'function') {
                o.isDraggable = false;
                o[what] = value;
            } else if (typeof value === 'string') {
                o.isDraggable = false;
                o[what] = JXG.createFunction(value, this.board, null, true);
                o[what + 'jc'] = value;
            }

            o[what].origin = value;

            this.board.update();
        } else if (o.type && o.elementClass && o.visProp) {
            par[what] = value;
            o.setProperty(par);
        } else {
            o[what] = value;
        }
    },

    /**
     * Encode characters outside the ASCII table into HTML Entities, because JavaScript or JS/CC can't handle a RegEx
     * applied to a string with unicode characters.
     * @param {String} string
     * @returns {String}
     */
    utf8_encode : function (string) {
        var utftext = [], n, c;

        for (n = 0; n < string.length; n++) {
            c = string.charCodeAt(n);

            if (c < 128) {
                utftext.push(String.fromCharCode(c));
            } else {
                utftext.push('&#x' + c.toString(16) + ';');
            }

        }

        return utftext.join('');
    },

    /**
     * Parses JessieCode
     * @param {String} code
     * @param {Boolean} [geonext=false] Geonext compatibility mode.
     */
    parse: function (code, geonext, dontstore) {
        var error_cnt = 0,
            error_off = [],
            error_la = [],
            that = this,
            to,
            replacegxt = ['Abs', 'ACos', 'ASin', 'ATan','Ceil','Cos','Exp','Factorial','Floor','Log','Max','Min','Random','Round','Sin','Sqrt','Tan','Trunc', 'If', 'Deg', 'Rad', 'Dist'],
            regex, setTextBackup = JXG.Text.prototype.setText,
            ccode = code.replace(/\r\n/g,'\n').split('\n'), i, j, cleaned = [];
        
        if (!dontstore) {
            this.code += code + '\n';
        }
        
        JXG.Text.prototype.setText = JXG.Text.prototype.setTextJessieCode;

        try {
            if (!JXG.exists(geonext)) {
                geonext = false;
            }

            for (i = 0; i < ccode.length; i++) {
                if (!(JXG.trim(ccode[i])[0] === '/' && JXG.trim(ccode[i])[1] === '/')) {
                    if (geonext) {
                        for (j = 0; j < replacegxt.length; j++) {
                            regex = new RegExp(replacegxt[j] + "\\(", 'g');
                            ccode[i] = ccode[i].replace(regex, replacegxt[j].toLowerCase() + '(');
                        }
                    }

                    cleaned.push(ccode[i]);
                } else {
                    cleaned.push('');
                }
            }
            code = cleaned.join('\n');
            code = this.utf8_encode(code);

            if ((error_cnt = this._parse(code, error_off, error_la)) > 0) {
                for (i = 0; i < error_cnt; i++) {
                    this.line = error_off[i].line;
                    this._error("Parse error in line " + error_off[i].line + " near >"  + code.substr( error_off[i].offset, 30 ) + "<, expecting \"" + error_la[i].join() + "\"");
                }
            }
        } catch (e) {
            // make sure the original text method is back in place
            JXG.Text.prototype.setText = setTextBackup;
            
            // rethrow
            throw e;
        }
        
        JXG.Text.prototype.setText = setTextBackup;
    },

    /**
     * Parses a JessieCode snippet, e.g. "3+4", and wraps it into a function, if desired.
     * @param {String} code A small snippet of JessieCode. Must not be an assignment.
     * @param {Boolean} funwrap If true, the code is wrapped in a function.
     * @param {String} varname Name of the parameter(s)
     * @param {Boolean} [geonext=false] Geonext compatibility mode.
     */
    snippet: function (code, funwrap, varname, geonext) {
        var vname, c, tmp, result;

        vname = 'jxg__tmp__intern_' + JXG.Util.genUUID().replace(/\-/g, '');

        if (!JXG.exists(funwrap)) {
            funwrap = true;
        }

        if (!JXG.exists(varname)) {
            varname = '';
        }

        if (!JXG.exists(geonext)) {
            geonext = false;
        }

        // just in case...
        tmp = this.sstack[0][vname];

        this.countLines = false;

        c = vname + ' = ' + (funwrap ? ' function (' + varname + ') { return ' : '') + code + (funwrap ? '; }' : '') + ';';
        this.parse(c, geonext, true);

        result = this.sstack[0][vname];
        if (JXG.exists(tmp)) {
            this.sstack[0][vname] = tmp;
        } else {
            delete this.sstack[0][vname];
        }

        this.countLines = true;

        return result;
    },

    /**
     * Traverses through the given subtree and changes all values of nodes with the replaced flag set by
     * {@link JXG.JessieCode#replaceNames} to the name of the element (if not empty).
     * @param {Object} node
     */
    replaceIDs: function (node) {
        var i, v;

        if (node.replaced) {
            // these children exist, if node.replaced is set.
            v = this.board.objects[node.children[1].children[0].value];
            if (JXG.exists(v) && JXG.exists(v) && v.name !== '') {
                node.type = 'node_var';
                node.value = v.name;
                // maybe it's not necessary, but just to be sure that everything's cleaned up we better delete all
                // children and the replaced flag
                node.children.length = 0;
                delete node.replaced;
            }
        }

        if (node.children) {
            // assignments are first evaluated on the right hand side
            for (i = node.children.length ; i > 0; i--) {
                if (JXG.exists(node.children[i-1])) {
                    node.children[i-1] = this.replaceIDs(node.children[i-1]);
                }

            }
        }

        return node;
    },

    /**
     * Traverses through the given subtree and changes all elements referenced by names through referencing them by ID.
     * An identifier is only replaced if it is not found in all scopes above the current scope and if it
     * has not been blacklisted within the codeblock determined by the given subtree.
     * @param {Object} node
     */
    replaceNames: function (node) {
        var i, v;

        v = node.value;

        // we are interested only in nodes of type node_var and node_op > op_lhs.
        // currently, we are not checking if the id is a local variable. in this case, we're stuck anyway.

        if (node.type == 'node_op' && v == 'op_lhs' && node.children.length === 1) {
            this.isLHS = true;
        } else if (node.type == 'node_var') {
            if (this.isLHS) {
                this.letvar(v, true);
            } else if (!JXG.exists(this.getvar(v, true)) && JXG.exists(this.board.elementsByName[v])) {
                node = this.createReplacementNode(node);
            }
        }

        if (node.children) {
            // assignments are first evaluated on the right hand side
            for (i = node.children.length ; i > 0; i--) {
                if (JXG.exists(node.children[i-1])) {
                    node.children[i-1] = this.replaceNames(node.children[i-1]);
                }

            }
        }

        if (node.type == 'node_op' && node.value == 'op_lhs' && node.children.length === 1) {
            this.isLHS = false;
        }

        return node;
    },

    /**
     * Replaces node_var nodes with node_op&gt;op_execfun nodes, calling the internal $() function with the id of the
     * element accessed by the node_var node.
     * @param {Object} node
     * @returns {Object} op_execfun node
     */
    createReplacementNode: function (node) {
        var v = node.value,
            el = this.board.elementsByName[v];

        node = this.createNode('node_op', 'op_execfun',
            this.createNode('node_var', '$'),
            this.createNode('node_op', 'op_param',
                this.createNode('node_str', el.id)
            )
        );

        node.replaced = true;

        return node;
    },

    /**
     * Search the parse tree below <tt>node</tt> for <em>stationary</em> dependencies, i.e. dependencies hard coded into
     * the function.
     * @param {Object} node
     * @param {Object} result An object where the referenced elements will be stored. Access key is their id.
     */
    collectDependencies: function (node, result) {
        var i, v, e;

        v = node.value;

        if (node.type == 'node_var') {
            e = this.getvar(v);
            if (e && e.visProp && e.type && e.elementClass && e.id) {
                result[e.id] = e;
            }
        }

        // the $()-function-calls are special because their parameter is given as a string, not as a node_var.
        if (node.type == 'node_op' && node.value == 'op_execfun' && node.children.length > 1 && node.children[0].value == '$' && node.children[1].children.length > 0) {
            e = node.children[1].children[0].value;
            result[e] = this.board.objects[e];
        }

        if (node.children) {
            for (i = node.children.length; i > 0; i--) {
                if (JXG.exists(node.children[i-1])) {
                    this.collectDependencies(node.children[i-1], result);
                }

            }
        }
    },

    resolveProperty: function (e, v, compile) {
        compile = JXG.def(compile, false);

        // is it a geometry element or a board?
        if (e /*&& e.type && e.elementClass*/ && e.methodMap) {
            // yeah, it is. but what does the user want?
            if (v === 'label') {
                // he wants to access the label properties!
                // adjust the base object...
                e = e.label;
                // and the property we are accessing
                v = 'content';
            } else {
                // ok, it's not the label he wants to change
                // well, what then?
                if (JXG.exists(e.subs) && JXG.exists(e.subs[v])) {
                    // a subelement it is, good sir.
                    e = e.subs;
                } else if (JXG.exists(e.methodMap[v])) {
                    // the user wants to call a method
                    v = e.methodMap[v];
                } else {
                    // the user wants to change an attribute
                    e = e.visProp;
                    v = v.toLowerCase();
                }
            }
        }

        if (!JXG.exists(e)) {
            this._error(e + ' is not an object');
        }

        if (!JXG.exists(e[v])) {
            this._error('unknown property ' + v);
        }

        if (compile && typeof e[v] === 'function') {
            return function () { return e[v].apply(e, arguments); };
        }

        return e[v];
    },

    /**
     * Executes a parse subtree.
     * @param {Object} node
     * @returns Something
     * @private
     */
    execute: function (node) {
        var ret, v, i, e, parents = [];

        ret = 0;

        if (!node)
            return ret;

        this.line = node.line;
        this.col = node.col;

        switch (node.type) {
            case 'node_op':
                switch (node.value) {
                    case 'op_none':
                        if (node.children[0]) {
                            this.execute(node.children[0]);
                        }
                        if (node.children[1]) {
                            ret = this.execute(node.children[1]);
                        }
                        break;
                    case 'op_assign':
                        v = this.execute(node.children[0]);
                        this.lhs[this.scope] = v[1];

                        if (v[0].type && v[0].elementClass && v[0].methodMap && v[1] === 'label') {
                            this._error('Left-hand side of assignment is read-only.');
                        }

                        if (v[0] !== this.sstack[this.scope] || (JXG.isArray(v[0]) && typeof v[1] === 'number')) {
                            // it is either an array component being set or a property of an object.
                            this.setProp(v[0], v[1], this.execute(node.children[1]));
                        } else {
                            // this is just a local variable inside JessieCode
                            this.letvar(v[1], this.execute(node.children[1]));
                        }

                        this.lhs[this.scope] = 0;
                        break;
                    case 'op_noassign':
                        ret = this.execute(node.children[0]);
                        break;
                    case 'op_if':
                        if (this.execute(node.children[0])) {
                            ret = this.execute(node.children[1]);
                        }
                        break;
                    case 'op_if_else':
                        if (this.execute(node.children[0])) {
                            ret = this.execute(node.children[1]);
                        } else {
                            ret = this.execute(node.children[2]);
                        }
                        break;
                    case 'op_while':
                        while (this.execute(node.children[0])) {
                            this.execute(node.children[1]);
                        }
                        break;
                    case 'op_do':
                        do {
                            this.execute(node.children[0]);
                        } while (this.execute(node.children[1]));
                        break;
                    case 'op_for':
                        for (this.execute(node.children[0]); this.execute(node.children[1]); this.execute(node.children[2])) {
                            this.execute(node.children[3]);
                        }
                        break;
                    case 'op_param':
                        if (node.children[1]) {
                            this.execute(node.children[1]);
                        }

                        ret = node.children[0];
                        this.pstack[this.pscope].push(ret);
                        if (this.dpstack[this.pscope]) {
                            this.dpstack[this.pscope].push({
                                line: node.children[0].line,
                                col: node.children[0].col
                            });
                        }
                        break;
                    case 'op_paramdef':
                        if (node.children[1]) {
                            this.execute(node.children[1]);
                        }

                        ret = node.children[0];
                        this.pstack[this.pscope].push(ret);
                        break;
                    case 'op_proplst':
                        if (node.children[0]) {
                            this.execute(node.children[0]);
                        }
                        if (node.children[1]) {
                            this.execute(node.children[1]);
                        }
                        break;
                    case 'op_proplst_val':
                        this.propstack.push({});
                        this.propscope++;

                        this.execute(node.children[0]);
                        ret = this.propstack[this.propscope];

                        this.propstack.pop();
                        this.propscope--;
                        break;
                    case 'op_prop':
                        // child 0: Identifier
                        // child 1: Value
                        this.propstack[this.propscope][node.children[0]] = this.execute(node.children[1]);
                        break;
                    case 'op_array':
                        var l;

                        this.pstack.push([]);
                        this.pscope++;

                        this.execute(node.children[0]);

                        ret = [];
                        l = this.pstack[this.pscope].length;

                        for (i = 0; i < l; i++) {
                            ret.push(this.execute(this.pstack[this.pscope][i]));
                        }

                        this.pstack.pop();
                        this.pscope--;

                        break;
                    case 'op_extvalue':
                        var undef;
                        
                        ret = this.execute(node.children[0]);
                        i = this.execute(node.children[1]);

                        if (typeof i === 'number' && Math.abs(Math.round(i) - i) < JXG.Math.eps) {
                            ret = ret[i];
                        } else {
                            ret = undef;
                        }
                        break;
                    case 'op_return':
                        if (this.scope === 0) {
                            this._error('Unexpected return.');
                        } else {
                            return this.execute(node.children[0]);
                        }
                        break;
                    case 'op_function':
                        this.pstack.push([]);
                        this.pscope++;

                        // parse the parameter list
                        // after this, the parameters are in pstack
                        this.execute(node.children[0]);

                        if (this.board.options.jc.compile) {
                            this.sstack.push({});
                            this.scope++;

                            this.isLHS = false;

                            for (i = 0; i < this.pstack[this.pscope].length; i++) {
                                this.sstack[this.scope][this.pstack[this.pscope][i]] = this.pstack[this.pscope][i];
                            }

                            this.replaceNames(node.children[1]);

                            ret = (function ($jc$) {
                                var p = $jc$.pstack[$jc$.pscope].join(', '),
                                    str = 'var f = function (' + p + ') {\n$jc$.sstack.push([]);\n$jc$.scope++;\nvar r = (function () {\n' + $jc$.compile(node.children[1], true) + '})();\n$jc$.sstack.pop();\n$jc$.scope--;\nreturn r;\n}; f;';
                                // the function code formatted:
                                /*
                                var f = function (_parameters_) {
                                    // handle the stack
                                    $jc$.sstack.push([]);
                                    $jc$.scope++;

                                    // this is required for stack handling: usually at some point in a function
                                    // there's a return statement, that prevents the cleanup of the stack.
                                    var r = (function () {
                                        _compiledcode_;
                                    })();

                                    // clean up the stack
                                    $jc$.sstack.pop();
                                    $jc$.scope--;

                                    // return the result
                                    return r;
                                };
                                f;   // the return value of eval()
                                */

                                try{
                                    return eval(str);
                                } catch (e) {
                                    //$jc$._error('catch errors. super simple stuff.', e.toString())
                                    throw e;
                                    return function () {};
                                }
                            })(this);

                            // clean up scope
                            this.sstack.pop();
                            this.scope--;
                        } else {
                            ret = (function (_pstack, that) {
                                return function () {
                                    var r;

                                    that.sstack.push({});
                                    that.scope++;
                                    for (r = 0; r < _pstack.length; r++) {
                                        that.sstack[that.scope][_pstack[r]] = arguments[r];
                                    }

                                    r = that.execute(node.children[1]);

                                    that.sstack.pop();
                                    that.scope--;
                                    return r;
                                };
                            })(this.pstack[this.pscope], this);
                        }

                        ret.node = node;
                        ret.toJS = ret.toString;
                        ret.toString = (function (_that) {
                            return function () {
                                return _that.compile(_that.replaceIDs(JXG.deepCopy(node)));
                            };
                        })(this);

                        ret.deps = {};
                        this.collectDependencies(node.children[1], ret.deps);

                        this.pstack.pop();
                        this.pscope--;
                        break;
                    case 'op_execfun':
                        // node.children:
                        //   [0]: Name of the function
                        //   [1]: Parameter list as a parse subtree
                        //   [2]: Properties, only used in case of a create function
                        var fun, attr, sc;

                        this.pstack.push([]);
                        this.dpstack.push([]);
                        this.pscope++;
                        
                        // parse the parameter list
                        // after this, the parameters are in pstack
                        this.execute(node.children[1]);

                        // parse the properties only if given
                        if (typeof node.children[2] !== 'undefined') {
                            if (node.children[3]) {
                                this.pstack.push([]);
                                this.dpstack.push([]);
                                this.pscope++;
                                
                                this.execute(node.children[2]);
                                attr = {};
                                for (i = 0; i < this.pstack[this.pscope].length; i++) {
                                    attr = JXG.deepCopy(attr, this.execute(this.pstack[this.pscope][i]), true);
                                }
                                
                                this.pscope--;
                                this.pstack.pop();
                                this.dpstack.pop();
                            } else {
                                attr = this.execute(node.children[2]);
                            }
                        }

                        // look up the variables name in the variable table
                        fun = this.execute(node.children[0]);

                        // determine the scope the function wants to run in
                        if (fun && fun.sc) {
                            sc = fun.sc;
                        } else {
                            sc = this;
                        }
                        
                        if (!fun.creator && typeof node.children[2] !== 'undefined') {
                            this._error('Unexpected value. Only element creators are allowed to have a value after the function call.');
                        }

                        // interpret ALL the parameters
                        for(i = 0; i < this.pstack[this.pscope].length; i++) {
                            parents[i] = this.execute(this.pstack[this.pscope][i]);
                        }
                        // check for the function in the variable table
                        if (typeof fun === 'function' && !fun.creator) {
                            ret = fun.apply(sc, parents);
                        } else if (typeof fun === 'function' && !!fun.creator) {
                            e = this.line;
                            // creator methods are the only ones that take properties, hence this special case
                            try {
                                /*this._log(node.children[0].value + '@' + this.line + ':' + node.col);
                                for (i = 0; i < this.pstack[this.pscope].length; i++) {
                                    this._log(parents[i] + '@' + this.dpstack[this.pscope][i].line + ':' + this.dpstack[this.pscope][i].col);
                                }*/
                                ret = fun(parents, attr);
                                ret.jcLineStart = e;
                                ret.jcLineEnd = node.line;

                                for (i = e; i <= node.line; i++) {
                                    this.lineToElement[i] = ret;
                                }

                                ret.debugParents = this.dpstack[this.pscope];
                            } catch (ex) {
                                this._error(ex.toString(), e);
                            }
                        } else {
                            this._error('Function \'' + fun + '\' is undefined.');
                        }

                        // clear parameter stack
                        this.pstack.pop();
                        this.dpstack.pop();
                        this.pscope--;
                        break;
                    case 'op_property':
                        e = this.execute(node.children[0]);
                        v = node.children[1];

                        ret = this.resolveProperty(e, v, false);

                        // set the scope, in case this is a method the user wants to call
                        if (JXG.exists(ret)) {
                            ret.sc = e;
                        }

                        break;
                    case 'op_lhs':
                        v = node.children[0];

                        // we have a subtree here (in case this is an array component)
                        if (v.children && v.type && v.value) {
                            v = this.execute(v);
                        }

                        if (node.children.length === 1) {
                            e = this.sstack[this.scope];
                        } else {
                            e = this.execute(node.children[1]);

                            if (e.type && e.elementClass && v.toLowerCase && v.toLowerCase() !== 'x' && v.toLowerCase() !== 'y') {
                                v = v.toLowerCase();
                            }
                        }

                        ret = [e, v];
                        break;
                    case 'op_use':
                        // node.children:
                        //   [0]: A string providing the id of the div the board is in.
                        var found = false;

                        // search all the boards for the one with the appropriate container div
                        for(var b in JXG.JSXGraph.boards) {
                            if(JXG.JSXGraph.boards[b].container === node.children[0].toString()) {
                                this.use(JXG.JSXGraph.boards[b]);
                                found = true;
                            }
                        }

                        if(!found)
                            this._error('Board \'' + node.children[0].toString() + '\' not found!');
                        break;
                    case 'op_delete':
                        v = this.getvar(node.children[0]);

                        if (typeof v === 'object' && JXG.exists(v.type) && JXG.exists(v.elementClass)) {
                            this.board.removeObject(v);
                        }
                        break;
                    case 'op_equ':
                        ret = this.execute(node.children[0]) == this.execute(node.children[1]);
                        break;
                    case 'op_neq':
                        ret = this.execute(node.children[0]) != this.execute(node.children[1]);
                        break;
                    case 'op_approx':
                        ret = Math.abs(this.execute(node.children[0]) - this.execute(node.children[1])) < JXG.Math.eps;
                        break;
                    case 'op_grt':
                        ret = this.execute(node.children[0]) > this.execute(node.children[1]);
                        break;
                    case 'op_lot':
                        ret = this.execute(node.children[0]) < this.execute(node.children[1]);
                        break;
                    case 'op_gre':
                        ret = this.execute(node.children[0]) >= this.execute(node.children[1]);
                        break;
                    case 'op_loe':
                        ret = this.execute(node.children[0]) <= this.execute(node.children[1]);
                        break;
                    case 'op_or':
                        ret = this.execute(node.children[0]) || this.execute(node.children[1]);
                        break;
                    case 'op_and':
                        ret = this.execute(node.children[0]) && this.execute(node.children[1]);
                        break;
                    case 'op_not':
                        ret = !this.execute(node.children[0]);
                        break;
                    case 'op_add':
                        ret = JXG.Math.Statistics.add(this.execute(node.children[0]), this.execute(node.children[1]));
                        break;
                    case 'op_sub':
                        ret = JXG.Math.Statistics.subtract(this.execute(node.children[0]), this.execute(node.children[1]));
                        break;
                    case 'op_div':
                        ret = JXG.Math.Statistics.div(this.execute(node.children[0]), this.execute(node.children[1]));
                        break;
                    case 'op_mod':
                        // use mathematical modulo, JavaScript implements the symmetric modulo.
                        ret = JXG.Math.Statistics.mod(this.execute(node.children[0]), this.execute(node.children[1]), true);
                        break;
                    case 'op_mul':
                        ret = this.mul(this.execute(node.children[0]), this.execute(node.children[1]));
                        break;
                    case 'op_exp':
                        ret = Math.pow(this.execute(node.children[0]),  this.execute(node.children[1]));
                        break;
                    case 'op_neg':
                        ret = this.execute(node.children[0]) * -1;
                        break;
                }
                break;

            case 'node_var':
                ret = this.getvar(node.value);
                break;

            case 'node_const':
                ret = Number(node.value);
                break;

            case 'node_const_bool':
                ret = node.value.toLowerCase() !== 'false';
                break;

            case 'node_str':
                ret = node.value;
                break;
        }

        return ret;
    },

    /**
     * Compiles a parse tree back to JessieCode.
     * @param {Object} node
     * @param {Boolean} [js=false] Currently ignored. Compile either to JavaScript or back to JessieCode (required for the UI).
     * @returns Something
     * @private
     */
    compile: function (node, js) {
        var ret, i, e, v;

        ret = '';

        if (!JXG.exists(js)) {
            js = false
        }

        if (!node)
            return ret;

        switch (node.type) {
            case 'node_op':
                switch (node.value) {
                    case 'op_none':
                        if (node.children[0]) {
                            ret = this.compile(node.children[0], js);
                        }
                        if (node.children[1]) {
                            ret += this.compile(node.children[1], js);
                        }
                        break;
                    case 'op_assign':
                        e = this.compile(node.children[0], js);
                        if (js) {
                            if (JXG.isArray(e)) {
                                ret = '$jc$.setProp(' + e[0] + ', \'' + e[1] + '\', ' + this.compile(node.children[1], js) + ');\n';
                            } else {
                                if (this.isLocalVariable(e) !== this.scope) {
                                    this.sstack[this.scope][e] = true;
                                }
                                ret = '$jc$.sstack[' + this.scope + '][\'' + e + '\'] = ' + this.compile(node.children[1], js) + ';\n';
                            }
                        } else {
                            ret = e + ' = ' + this.compile(node.children[1], js) + ';\n';
                        }

                        break;
                    case 'op_noassign':
                        ret = this.compile(node.children[0], js) + ';\n';
                        break;
                    case 'op_if':
                        ret = ' if (' + this.compile(node.children[0], js) + ') ' + this.compile(node.children[1], js);
                        break;
                    case 'op_if_else':
                        ret = ' if (' + this.compile(node.children[0], js) + ')' + this.compile(node.children[1], js);
                        ret += ' else ' + this.compile(node.children[2], js);
                        break;
                    case 'op_while':
                        ret = ' while (' + this.compile(node.children[0], js) + ') {\n' + this.compile(node.children[1], js) + '}\n';
                        break;
                    case 'op_do':
                        ret = ' do {\n' + this.compile(node.children[0], js) + '} while (' + this.compile(node.children[1], js) + ');\n';
                        break;
                    case 'op_for':
                        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';
                        break;
                    case 'op_param':
                        if (node.children[1]) {
                            ret = this.compile(node.children[1], js) + ', ';
                        }

                        ret += this.compile(node.children[0], js);
                        break;
                    case 'op_paramdef':
                        if (node.children[1]) {
                            ret = this.compile(node.children[1], js) + ', ';
                        }

                        ret += node.children[0];
                        break;
                    case 'op_proplst':
                        if (node.children[0]) {
                            ret = this.compile(node.children[0], js) + ', ';
                        }

                        ret += this.compile(node.children[1], js);
                        break;
                    case 'op_prop':
                        // child 0: Identifier
                        // child 1: Value
                        ret = node.children[0] + ': ' + this.compile(node.children[1], js);
                        break;
                    case 'op_proplst_val':
                        ret = /*(js ? '{' : '<<') +*/ this.compile(node.children[0], js) /*+ (js ? '}' : '>>')*/;
                        break;
                    case 'op_array':
                        ret = '[' + this.compile(node.children[0], js) + ']';
                        break;
                    case 'op_extvalue':
                        ret = this.compile(node.children[0], js) + '[' + this.compile(node.children[1], js) + ']';
                        break;
                    case 'op_return':
                        ret = ' return ' + this.compile(node.children[0], js) + ';\n';
                        break;
                    case 'op_function':
                        ret = ' function (' + this.compile(node.children[0], js) + ') {\n' + this.compile(node.children[1], js) + '}';
                        break;
                    case 'op_execfun':
                        // parse the properties only if given
                        if (node.children[2]) {
                            e = this.compile(node.children[2], js);
                            
                            if (js) {
                                e = '$jc$.mergeAttributes(' + e + ')';
                            }
                        }
                        node.children[0].withProps = !!node.children[2];
                        ret = this.compile(node.children[0], js) + '(' + this.compile(node.children[1], js) + (node.children[2] && js ? ', ' + e : '') + ')' + (node.children[2] && !js ? e : '');

                        // save us a function call when compiled to javascript
                        if (js && node.children[0].value === '$') {
                            ret = '$jc$.board.objects[' + this.compile(node.children[1], js) + ']';
                        }

                        break;
                    case 'op_property':
                        if (js && node.children[1] !== 'X' && node.children[1] !== 'Y') {
                            ret = '$jc$.resolveProperty(' + this.compile(node.children[0], js) + ', \'' + node.children[1] + '\', true)';
                        } else {
                            ret = this.compile(node.children[0], js) + '.' + node.children[1];
                        }
                        break;
                    case 'op_lhs':
                        if (node.children.length === 1) {
                            ret = node.children[0];
                        } else if (node.children[2] === 'dot') {
                            if (js) {
                                ret = [this.compile(node.children[1], js), node.children[0]];
                            } else {
                                ret = this.compile(node.children[1], js) + '.' + node.children[0];
                            }
                        } else if (node.children[2] === 'bracket') {
                            if (js) {
                                ret = [this.compile(node.children[1], js), this.compile(node.children[0], js)];
                            } else {
                                ret = this.compile(node.children[1], js) + '[' + this.compile(node.children[0], js) + ']';
                            }
                        }
                        break;
                    case 'op_use':
                        if (js) {
                            ret = '$jc$.use(JXG.JSXGraph.boards[\'' + node.children[0] + '\'])';
                        } else {
                            ret = 'use ' + node.children[0] + ';';
                        }
                        break;
                    case 'op_delete':
                        ret = 'delete ' + node.children[0];
                        break;
                    case 'op_equ':
                        ret = '(' + this.compile(node.children[0], js) + ' == ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_neq':
                        ret = '(' + this.compile(node.children[0], js) + ' != ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_approx':
                        ret = '(' + this.compile(node.children[0], js) + ' ~= ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_grt':
                        ret = '(' + this.compile(node.children[0], js) + ' > ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_lot':
                        ret = '(' + this.compile(node.children[0], js) + ' < ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_gre':
                        ret = '(' + this.compile(node.children[0], js) + ' >= ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_loe':
                        ret = '(' + this.compile(node.children[0], js) + ' <= ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_or':
                        ret = '(' + this.compile(node.children[0], js) + ' || ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_and':
                        ret = '(' + this.compile(node.children[0], js) + ' && ' + this.compile(node.children[1], js) + ')';
                        break;
                    case 'op_not':
                        ret = '!(' + this.compile(node.children[0], js) + ')';
                        break;
                    case 'op_add':
                        if (js) {
                            ret = 'JXG.Math.Statistics.add(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
                        } else {
                            ret = '(' + this.compile(node.children[0], js) + ' + ' + this.compile(node.children[1], js) + ')';
                        }
                        break;
                    case 'op_sub':
                        if (js) {
                            ret = 'JXG.Math.Statistics.subtract(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
                        } else {
                            ret = '(' + this.compile(node.children[0], js) + ' - ' + this.compile(node.children[1], js) + ')';
                        }
                        break;
                    case 'op_div':
                        if (js) {
                            ret = 'JXG.Math.Statistics.div(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
                        } else {
                            ret = '(' + this.compile(node.children[0], js) + ' / ' + this.compile(node.children[1], js) + ')';
                        }
                        break;
                    case 'op_mod':
                        if (js) {
                            ret = 'JXG.Math.mod(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ', true)';
                        } else {
                            ret = '(' + this.compile(node.children[0], js) + ' % ' + this.compile(node.children[1], js) + ')';
                        }
                        break;
                    case 'op_mul':
                        if (js) {
                            ret = '$jc$.mul(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
                        } else {
                            ret = '(' + this.compile(node.children[0], js) + ' * ' + this.compile(node.children[1], js) + ')';
                        }
                        break;
                    case 'op_exp':
                        if (js) {
                            ret = 'Math.pow(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
                        } else {
                            ret = '(' + this.compile(node.children[0], js) + '^' + this.compile(node.children[1], js) + ')';
                        }
                        break;
                    case 'op_neg':
                        ret = '(-' + this.compile(node.children[0], js) + ')';
                        break;
                }
                break;

            case 'node_var':
                if (js) {
                    //ret = '$jc$.getvar(\'' + node.value + '\')';
                    ret = this.getvarJS(node.value, false, node.withProps);
                } else {
                    ret = node.value;
                }
                break;

            case 'node_const':
                ret = node.value;
                break;

            case 'node_const_bool':
                ret = node.value;
                break;

            case 'node_str':
                ret = '\'' + node.value.replace(/'/g, '\\\'') + '\'';
                break;
        }

        if (node.needsBrackets) {
            ret = '{\n' + ret + '}\n';
        }

        return ret;
    },

    /**
     * This is used as the global X() function.
     * @param {JXG.Point|JXG.Text} e
     * @returns {Number}
     */
    X: function (e) {
        return e.X();
    },

    /**
     * This is used as the global Y() function.
     * @param {JXG.Point|JXG.Text} e
     * @returns {Number}
     */
    Y: function (e) {
        return e.Y();
    },

    /**
     * This is used as the global V() function.
     * @param {Glider|Slider} e
     * @returns {%}
     */
    V: function (e) {
        return e.Value();
    },

    /**
     * This is used as the global L() function.
     * @param {JXG.Line} e
     * @returns {Number}
     */
    L: function (e) {
        return e.L();
    },

    /**
     * This is used as the global dist() function.
     * @param {JXG.Point} p1
     * @param {JXG.Point} p2
     * @returns {Number}
     */
    dist: function (p1, p2) {
        if (!JXG.exists(p1) || !JXG.exists(p1.Dist)) {
            this._error('Error: Can\'t calculate distance.');
        }

        return p1.Dist(p2);
    },

    /**
     * Multiplication of vectors and numbers
     * @param {Number|Array} a
     * @param {Number|Array} b
     * @returns {Number|Array} (Inner) product of the given input values.
     */
    mul: function (a, b) {
        if (JXG.isArray(a) * JXG.isArray(b)) {
            return JXG.Math.innerProduct(a, b, Math.min(a.length, b.length));
        } else {
            return JXG.Math.Statistics.multiply(a, b);
        }
    },


    use: function (board) {
        this.board = board;
        this.builtIn['$board'] = board;
        this.builtIn['$board'].src = '$jc$.board';
    },

    /**
     * Find the first symbol to the given value from the given scope upwards.
     * @param {%} v Value
     * @param {Number} [scope=-1] The scope, default is to start with current scope (-1).
     * @returns {Array} An array containing the symbol and the scope if a symbol could be found,
     * an empty array otherwise;
     */
    findSymbol: function (v, scope) {
        var s, i;

        scope = JXG.def(scope, -1);

        if (scope === -1) {
            scope = this.scope;
        }

        for (s = scope; s >= 0; s--) {
            for (i in this.sstack[s]) {
                if (this.sstack[s][i] === v) {
                    return [i, s];
                }
            }
        }

        return [];
    },

    /**
     * Defines built in methods and constants.
     * @returns {Object} BuiltIn control object
     */
    defineBuiltIn: function () {
        var that = this,
            builtIn = {
                PI: Math.PI,
                EULER: Math.E,
                X: that.X,
                Y: that.Y,
                V: that.V,
                L: that.L,
                dist: that.dist,
                rad: JXG.Math.Geometry.rad,
                deg: JXG.Math.Geometry.trueAngle,
                factorial: JXG.Math.factorial,
                trunc: JXG.trunc,
                '$': that.getElementById,
                '$board': that.board
            };

        // special scopes for factorial, deg, and rad
        builtIn.rad.sc = JXG.Math.Geometry;
        builtIn.deg.sc = JXG.Math.Geometry;
        builtIn.factorial.sc = JXG.Math;

        // set the javascript equivalent for the builtIns
        // some of the anonymous functions should be replaced by global methods later on
        builtIn.PI.src = 'Math.PI';
        builtIn.EULER.src = 'Math.E';
        builtIn.X.src = '$jc$.X';
        builtIn.Y.src = '$jc$.Y';
        builtIn.V.src = '$jc$.V';
        builtIn.L.src = '$jc$.L';
        builtIn.dist.src = '$jc$.dist';
        builtIn.rad.src = 'JXG.Math.Geometry.rad';
        builtIn.deg.src = 'JXG.Math.Geometry.trueAngle';
        builtIn.factorial.src = 'JXG.Math.factorial';
        builtIn.trunc.src = 'JXG.trunc';
        // usually unused, see node_op > op_execfun
        builtIn['$'].src = '(function (n) { return JXG.getRef($jc$.board, n); })';
        if (builtIn['$board']) {
            builtIn['$board'].src = '$jc$.board';
        }

        return builtIn;
    },

    /**
     * Output a debugging message. Uses debug console, if available. Otherwise an HTML element with the
     * id "debug" and an innerHTML property is used.
     * @param {String} log
     * @private
     */
    _debug: function (log) {
        if(typeof console !== "undefined") {
            console.log(log);
        } else if(document && document.getElementById('debug') !== null) {
            document.getElementById('debug').innerHTML += log + '<br />';
        }
    },

    /**
     * Throws an exception with the given error message.
     * @param {String} msg Error message
     */
    _error: function (msg) {
        var e = new Error('Error(' + this.line + '): ' + msg);
        e.line = this.line;
        throw e;
    },

    /**
     * Output a warning message using {@link JXG#debug} and precedes the message with "Warning: ".
     * @param {String} msg
     */
    _warn: function (msg) {
        if(typeof console !== "undefined") {
            console.log('Warning(' + this.line + '): ' + msg);
        } else if(document && document.getElementById(this.warnLog) !== null) {
            document.getElementById(this.warnLog).innerHTML += 'Warning(' + this.line + '): ' + msg + '<br />';
        }
    },

    _log: function (msg) {
        if (typeof window === 'undefined' && typeof self !== 'undefined' && self.postMessage) {
            self.postMessage({type: 'log', msg: 'Log: ' + msg.toString()});
        } else {
            console.log('Log: ', arguments);
        }
    }

});

/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/



/*
    Default template driver for JS/CC generated parsers running as
    browser-based JavaScript/ECMAScript applications.
    
    WARNING:     This parser template will only run together with JSXGraph on a website.
    
    Features:
    - Parser trace messages
    - Integrated panic-mode error recovery
    
    Written 2007, 2008 by Jan Max Meyer, J.M.K S.F. Software Technologies
    Modified 2011 by Michael Gerhaeuser, JSXGraph
    
    This is in the public domain.
*/


JXG.extend(JXG.JessieCode.prototype, /** @lends JXG.JessieCode.prototype */ {
    /**
     * Internal lexer method.
     * @private
     */
    _lex: function (PCB) {
        var state,
            match = -1,
            match_pos = 0,
            start = 0,
            pos,
            chr;

        while (1) {
            state = 0;
            match = -1;
            match_pos = 0;
            start = 0;
            pos = PCB.offset + 1 + ( match_pos - start );

            do {

                pos--;
                state = 0;
                match = -2;
                start = pos;

                if( PCB.src.length <= start )
                    return 68;

                do {
                    chr = PCB.src.charCodeAt( pos );

switch( state )
{
	case 0:
		if( ( chr >= 9 && chr <= 10 ) || chr == 13 || chr == 32 ) state = 1;
		else if( chr == 33 ) state = 2;
		else if( chr == 35 ) state = 3;
		else if( chr == 36 || ( chr >= 65 && chr <= 67 ) || ( chr >= 71 && chr <= 72 ) || ( chr >= 74 && chr <= 77 ) || ( chr >= 79 && chr <= 81 ) || chr == 83 || chr == 86 || ( chr >= 88 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 99 ) || ( chr >= 103 && chr <= 104 ) || ( chr >= 106 && chr <= 113 ) || chr == 115 || chr == 118 || ( chr >= 120 && chr <= 122 ) ) state = 4;
		else if( chr == 37 ) state = 5;
		else if( chr == 40 ) state = 6;
		else if( chr == 41 ) state = 7;
		else if( chr == 42 ) state = 8;
		else if( chr == 43 ) state = 9;
		else if( chr == 44 ) state = 10;
		else if( chr == 45 ) state = 11;
		else if( chr == 46 ) state = 12;
		else if( chr == 47 ) state = 13;
		else if( ( chr >= 48 && chr <= 57 ) ) state = 14;
		else if( chr == 58 ) state = 15;
		else if( chr == 59 ) state = 16;
		else if( chr == 60 ) state = 17;
		else if( chr == 61 ) state = 18;
		else if( chr == 62 ) state = 19;
		else if( chr == 91 ) state = 20;
		else if( chr == 93 ) state = 21;
		else if( chr == 94 ) state = 22;
		else if( chr == 123 ) state = 23;
		else if( chr == 124 ) state = 24;
		else if( chr == 125 ) state = 25;
		else if( chr == 38 ) state = 49;
		else if( chr == 68 || chr == 100 ) state = 50;
		else if( chr == 39 ) state = 52;
		else if( chr == 73 || chr == 105 ) state = 53;
		else if( chr == 126 ) state = 54;
		else if( chr == 70 || chr == 102 ) state = 66;
		else if( chr == 78 ) state = 67;
		else if( chr == 85 || chr == 117 ) state = 68;
		else if( chr == 69 || chr == 101 ) state = 76;
		else if( chr == 84 || chr == 116 ) state = 77;
		else if( chr == 87 || chr == 119 ) state = 83;
		else if( chr == 82 || chr == 114 ) state = 87;
		else state = -1;
		break;

	case 1:
		state = -1;
		match = 2;
		match_pos = pos;
		break;

	case 2:
		if( chr == 61 ) state = 26;
		else state = -1;
		match = 31;
		match_pos = pos;
		break;

	case 3:
		state = -1;
		match = 41;
		match_pos = pos;
		break;

	case 4:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 5:
		state = -1;
		match = 35;
		match_pos = pos;
		break;

	case 6:
		state = -1;
		match = 38;
		match_pos = pos;
		break;

	case 7:
		state = -1;
		match = 39;
		match_pos = pos;
		break;

	case 8:
		state = -1;
		match = 36;
		match_pos = pos;
		break;

	case 9:
		state = -1;
		match = 32;
		match_pos = pos;
		break;

	case 10:
		state = -1;
		match = 40;
		match_pos = pos;
		break;

	case 11:
		state = -1;
		match = 33;
		match_pos = pos;
		break;

	case 12:
		if( ( chr >= 48 && chr <= 57 ) ) state = 29;
		else state = -1;
		match = 44;
		match_pos = pos;
		break;

	case 13:
		state = -1;
		match = 34;
		match_pos = pos;
		break;

	case 14:
		if( ( chr >= 48 && chr <= 57 ) ) state = 14;
		else if( chr == 46 ) state = 29;
		else state = -1;
		match = 48;
		match_pos = pos;
		break;

	case 15:
		state = -1;
		match = 42;
		match_pos = pos;
		break;

	case 16:
		state = -1;
		match = 20;
		match_pos = pos;
		break;

	case 17:
		if( chr == 60 ) state = 30;
		else if( chr == 61 ) state = 31;
		else state = -1;
		match = 28;
		match_pos = pos;
		break;

	case 18:
		if( chr == 61 ) state = 32;
		else state = -1;
		match = 21;
		match_pos = pos;
		break;

	case 19:
		if( chr == 61 ) state = 33;
		else if( chr == 62 ) state = 34;
		else state = -1;
		match = 27;
		match_pos = pos;
		break;

	case 20:
		state = -1;
		match = 16;
		match_pos = pos;
		break;

	case 21:
		state = -1;
		match = 17;
		match_pos = pos;
		break;

	case 22:
		state = -1;
		match = 37;
		match_pos = pos;
		break;

	case 23:
		state = -1;
		match = 18;
		match_pos = pos;
		break;

	case 24:
		if( chr == 124 ) state = 37;
		else state = -1;
		match = 43;
		match_pos = pos;
		break;

	case 25:
		state = -1;
		match = 19;
		match_pos = pos;
		break;

	case 26:
		state = -1;
		match = 23;
		match_pos = pos;
		break;

	case 27:
		state = -1;
		match = 30;
		match_pos = pos;
		break;

	case 28:
		state = -1;
		match = 47;
		match_pos = pos;
		break;

	case 29:
		if( ( chr >= 48 && chr <= 57 ) ) state = 29;
		else state = -1;
		match = 49;
		match_pos = pos;
		break;

	case 30:
		state = -1;
		match = 14;
		match_pos = pos;
		break;

	case 31:
		state = -1;
		match = 25;
		match_pos = pos;
		break;

	case 32:
		state = -1;
		match = 22;
		match_pos = pos;
		break;

	case 33:
		state = -1;
		match = 26;
		match_pos = pos;
		break;

	case 34:
		state = -1;
		match = 15;
		match_pos = pos;
		break;

	case 35:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 6;
		match_pos = pos;
		break;

	case 36:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 3;
		match_pos = pos;
		break;

	case 37:
		state = -1;
		match = 29;
		match_pos = pos;
		break;

	case 38:
		state = -1;
		match = 24;
		match_pos = pos;
		break;

	case 39:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 7;
		match_pos = pos;
		break;

	case 40:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 45;
		match_pos = pos;
		break;

	case 41:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 9;
		match_pos = pos;
		break;

	case 42:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 4;
		match_pos = pos;
		break;

	case 43:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 12;
		match_pos = pos;
		break;

	case 44:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 13;
		match_pos = pos;
		break;

	case 45:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 5;
		match_pos = pos;
		break;

	case 46:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 11;
		match_pos = pos;
		break;

	case 47:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 10;
		match_pos = pos;
		break;

	case 48:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else state = -1;
		match = 8;
		match_pos = pos;
		break;

	case 49:
		if( chr == 38 ) state = 27;
		else state = -1;
		break;

	case 50:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 78 ) || ( chr >= 80 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 110 ) || ( chr >= 112 && chr <= 122 ) ) state = 4;
		else if( chr == 79 || chr == 111 ) state = 35;
		else if( chr == 69 || chr == 101 ) state = 84;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 51:
		if( chr == 39 ) state = 28;
		else if( ( chr >= 0 && chr <= 38 ) || ( chr >= 40 && chr <= 91 ) || ( chr >= 93 && chr <= 254 ) ) state = 52;
		else if( chr == 92 ) state = 56;
		else state = -1;
		match = 47;
		match_pos = pos;
		break;

	case 52:
		if( chr == 39 ) state = 28;
		else if( ( chr >= 0 && chr <= 38 ) || ( chr >= 40 && chr <= 91 ) || ( chr >= 93 && chr <= 254 ) ) state = 52;
		else if( chr == 92 ) state = 56;
		else state = -1;
		break;

	case 53:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 69 ) || ( chr >= 71 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 101 ) || ( chr >= 103 && chr <= 122 ) ) state = 4;
		else if( chr == 70 || chr == 102 ) state = 36;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 54:
		if( chr == 61 ) state = 38;
		else state = -1;
		break;

	case 55:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 81 ) || ( chr >= 83 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 113 ) || ( chr >= 115 && chr <= 122 ) ) state = 4;
		else if( chr == 82 || chr == 114 ) state = 39;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 56:
		if( chr == 39 ) state = 51;
		else if( ( chr >= 0 && chr <= 38 ) || ( chr >= 40 && chr <= 91 ) || ( chr >= 93 && chr <= 254 ) ) state = 52;
		else if( chr == 92 ) state = 56;
		else state = -1;
		break;

	case 57:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 77 ) || ( chr >= 79 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 122 ) ) state = 4;
		else if( chr == 78 ) state = 40;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 58:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 41;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 59:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 42;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 60:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 43;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 61:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 44;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 62:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 45;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 63:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 46;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 64:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 77 ) || ( chr >= 79 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 109 ) || ( chr >= 111 && chr <= 122 ) ) state = 4;
		else if( chr == 78 || chr == 110 ) state = 47;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 65:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 77 ) || ( chr >= 79 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 109 ) || ( chr >= 111 && chr <= 122 ) ) state = 4;
		else if( chr == 78 || chr == 110 ) state = 48;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 66:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 66 && chr <= 78 ) || ( chr >= 80 && chr <= 84 ) || ( chr >= 86 && chr <= 90 ) || chr == 95 || ( chr >= 98 && chr <= 110 ) || ( chr >= 112 && chr <= 116 ) || ( chr >= 118 && chr <= 122 ) ) state = 4;
		else if( chr == 79 || chr == 111 ) state = 55;
		else if( chr == 65 || chr == 97 ) state = 78;
		else if( chr == 85 || chr == 117 ) state = 89;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 67:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 90 ) || chr == 95 || ( chr >= 98 && chr <= 122 ) ) state = 4;
		else if( chr == 97 ) state = 57;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 68:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 82 ) || ( chr >= 84 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 114 ) || ( chr >= 116 && chr <= 122 ) ) state = 4;
		else if( chr == 83 || chr == 115 ) state = 58;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 69:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 82 ) || ( chr >= 84 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 114 ) || ( chr >= 116 && chr <= 122 ) ) state = 4;
		else if( chr == 83 || chr == 115 ) state = 59;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 70:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 84 ) || ( chr >= 86 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 116 ) || ( chr >= 118 && chr <= 122 ) ) state = 4;
		else if( chr == 85 || chr == 117 ) state = 60;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 71:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 82 ) || ( chr >= 84 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 114 ) || ( chr >= 116 && chr <= 122 ) ) state = 4;
		else if( chr == 83 || chr == 115 ) state = 61;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 72:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 75 ) || ( chr >= 77 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 107 ) || ( chr >= 109 && chr <= 122 ) ) state = 4;
		else if( chr == 76 || chr == 108 ) state = 62;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 73:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 83 ) || ( chr >= 85 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 115 ) || ( chr >= 117 && chr <= 122 ) ) state = 4;
		else if( chr == 84 || chr == 116 ) state = 63;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 74:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 81 ) || ( chr >= 83 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 113 ) || ( chr >= 115 && chr <= 122 ) ) state = 4;
		else if( chr == 82 || chr == 114 ) state = 64;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 75:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 78 ) || ( chr >= 80 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 110 ) || ( chr >= 112 && chr <= 122 ) ) state = 4;
		else if( chr == 79 || chr == 111 ) state = 65;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 76:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 75 ) || ( chr >= 77 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 107 ) || ( chr >= 109 && chr <= 122 ) ) state = 4;
		else if( chr == 76 || chr == 108 ) state = 69;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 77:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 81 ) || ( chr >= 83 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 113 ) || ( chr >= 115 && chr <= 122 ) ) state = 4;
		else if( chr == 82 || chr == 114 ) state = 70;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 78:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 75 ) || ( chr >= 77 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 107 ) || ( chr >= 109 && chr <= 122 ) ) state = 4;
		else if( chr == 76 || chr == 108 ) state = 71;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 79:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 72 ) || ( chr >= 74 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 104 ) || ( chr >= 106 && chr <= 122 ) ) state = 4;
		else if( chr == 73 || chr == 105 ) state = 72;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 80:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 73;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 81:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 84 ) || ( chr >= 86 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 116 ) || ( chr >= 118 && chr <= 122 ) ) state = 4;
		else if( chr == 85 || chr == 117 ) state = 74;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 82:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 72 ) || ( chr >= 74 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 104 ) || ( chr >= 106 && chr <= 122 ) ) state = 4;
		else if( chr == 73 || chr == 105 ) state = 75;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 83:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 71 ) || ( chr >= 73 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 103 ) || ( chr >= 105 && chr <= 122 ) ) state = 4;
		else if( chr == 72 || chr == 104 ) state = 79;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 84:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 75 ) || ( chr >= 77 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 107 ) || ( chr >= 109 && chr <= 122 ) ) state = 4;
		else if( chr == 76 || chr == 108 ) state = 80;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 85:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 83 ) || ( chr >= 85 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 115 ) || ( chr >= 117 && chr <= 122 ) ) state = 4;
		else if( chr == 84 || chr == 116 ) state = 81;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 86:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 83 ) || ( chr >= 85 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 115 ) || ( chr >= 117 && chr <= 122 ) ) state = 4;
		else if( chr == 84 || chr == 116 ) state = 82;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 87:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 68 ) || ( chr >= 70 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 100 ) || ( chr >= 102 && chr <= 122 ) ) state = 4;
		else if( chr == 69 || chr == 101 ) state = 85;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 88:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 66 ) || ( chr >= 68 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 98 ) || ( chr >= 100 && chr <= 122 ) ) state = 4;
		else if( chr == 67 || chr == 99 ) state = 86;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

	case 89:
		if( ( chr >= 48 && chr <= 57 ) || ( chr >= 65 && chr <= 77 ) || ( chr >= 79 && chr <= 90 ) || chr == 95 || ( chr >= 97 && chr <= 109 ) || ( chr >= 111 && chr <= 122 ) ) state = 4;
		else if( chr == 78 || chr == 110 ) state = 88;
		else state = -1;
		match = 46;
		match_pos = pos;
		break;

}



                    //Line- and column-counter
                    if( state > -1 ) {
                        if( chr == 10 ) {
                            PCB.line++;
                            PCB.column = 0;
                            if (this.countLines) {
                                this.parCurLine = PCB.line;
                            }
                        }
                        PCB.column++;
                        if (this.countLines) {
                            this.parCurColumn = PCB.column;
                        }
                    }

                    pos++;

                } while( state > -1 );

            } while (2 > -1 && match == 2);

            if (match > -1) {
                PCB.att = PCB.src.substr( start, match_pos - start );
                PCB.offset = match_pos;
        
	if( match == 47 )
	{
		 PCB.att = PCB.att.substr( 1, PCB.att.length - 2 );
                                                                                PCB.att = PCB.att.replace( /\\\'/g, "\'" );    
		}

            } else {
                PCB.att = new String();
                match = -1;
            }

            break;
        }
        return match;
    },

    /**
     * Internal parse tree generator.
     * @param {String} src source code
     * @param {Array} err_off The positions where the errors occured are stored here.
     * @param {Array} err_la What the parser expected will be stored here.
     * @private
     */
    _parse: function (src, err_off, err_la) {
        var sstack = [],
            vstack = [],
            err_cnt = 0,
            act,
            rval,
            i,

            PCB = {
                la: 0,
                act: 0,
                offset: 0,
                src: src,
                att: '',
                line: 1,
                column: 1,
                error_step: 0
            };

/* Pop-Table */
var pop_tab = new Array(
	new Array( 0/* Program' */, 1 ),
	new Array( 50/* Program */, 2 ),
	new Array( 50/* Program */, 0 ),
	new Array( 52/* Stmt_List */, 2 ),
	new Array( 52/* Stmt_List */, 0 ),
	new Array( 53/* Param_List */, 3 ),
	new Array( 53/* Param_List */, 1 ),
	new Array( 53/* Param_List */, 0 ),
	new Array( 55/* Prop_List */, 3 ),
	new Array( 55/* Prop_List */, 1 ),
	new Array( 55/* Prop_List */, 0 ),
	new Array( 56/* Prop */, 3 ),
	new Array( 57/* Param_Def_List */, 3 ),
	new Array( 57/* Param_Def_List */, 1 ),
	new Array( 57/* Param_Def_List */, 0 ),
	new Array( 58/* Attr_List */, 3 ),
	new Array( 58/* Attr_List */, 1 ),
	new Array( 61/* Assign */, 3 ),
	new Array( 51/* Stmt */, 3 ),
	new Array( 51/* Stmt */, 5 ),
	new Array( 51/* Stmt */, 3 ),
	new Array( 51/* Stmt */, 5 ),
	new Array( 51/* Stmt */, 9 ),
	new Array( 51/* Stmt */, 3 ),
	new Array( 51/* Stmt */, 2 ),
	new Array( 51/* Stmt */, 2 ),
	new Array( 51/* Stmt */, 2 ),
	new Array( 51/* Stmt */, 2 ),
	new Array( 51/* Stmt */, 3 ),
	new Array( 51/* Stmt */, 1 ),
	new Array( 60/* Lhs */, 3 ),
	new Array( 60/* Lhs */, 4 ),
	new Array( 60/* Lhs */, 1 ),
	new Array( 54/* Expression */, 3 ),
	new Array( 54/* Expression */, 3 ),
	new Array( 54/* Expression */, 3 ),
	new Array( 54/* Expression */, 3 ),
	new Array( 54/* Expression */, 3 ),
	new Array( 54/* Expression */, 3 ),
	new Array( 54/* Expression */, 3 ),
	new Array( 54/* Expression */, 1 ),
	new Array( 63/* LogExp */, 3 ),
	new Array( 63/* LogExp */, 3 ),
	new Array( 63/* LogExp */, 2 ),
	new Array( 63/* LogExp */, 1 ),
	new Array( 62/* AddSubExp */, 3 ),
	new Array( 62/* AddSubExp */, 3 ),
	new Array( 62/* AddSubExp */, 1 ),
	new Array( 64/* MulDivExp */, 3 ),
	new Array( 64/* MulDivExp */, 3 ),
	new Array( 64/* MulDivExp */, 3 ),
	new Array( 64/* MulDivExp */, 1 ),
	new Array( 66/* ExpExp */, 3 ),
	new Array( 66/* ExpExp */, 1 ),
	new Array( 65/* NegExp */, 2 ),
	new Array( 65/* NegExp */, 2 ),
	new Array( 65/* NegExp */, 1 ),
	new Array( 59/* ExtValue */, 4 ),
	new Array( 59/* ExtValue */, 7 ),
	new Array( 59/* ExtValue */, 4 ),
	new Array( 59/* ExtValue */, 5 ),
	new Array( 59/* ExtValue */, 3 ),
	new Array( 59/* ExtValue */, 1 ),
	new Array( 67/* Value */, 1 ),
	new Array( 67/* Value */, 1 ),
	new Array( 67/* Value */, 1 ),
	new Array( 67/* Value */, 3 ),
	new Array( 67/* Value */, 1 ),
	new Array( 67/* Value */, 7 ),
	new Array( 67/* Value */, 3 ),
	new Array( 67/* Value */, 3 ),
	new Array( 67/* Value */, 1 ),
	new Array( 67/* Value */, 1 ),
	new Array( 67/* Value */, 1 )
);

/* Action-Table */
var act_tab = new Array(
	/* State 0 */ new Array(  ),
	/* State 1 */ new Array( 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 2 */ new Array(  ),
	/* State 3 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 4 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 5 */ new Array( 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 6 */ new Array( 38/* "(" */,41 ),
	/* State 7 */ new Array( 46/* "Identifier" */,42 ),
	/* State 8 */ new Array( 46/* "Identifier" */,43 ),
	/* State 9 */ new Array( 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 10 */ new Array( 20/* ";" */,45 ),
	/* State 11 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 , 20/* ";" */,53 ),
	/* State 12 */ new Array(  ),
	/* State 13 */ new Array(  ),
	/* State 14 */ new Array( 21/* "=" */,55 ),
	/* State 15 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 16 */ new Array( 44/* "." */,58 , 38/* "(" */,59 , 16/* "[" */,60 , 37/* "^" */,61 ),
	/* State 17 */ new Array( 21/* "=" */,-32 ),
	/* State 18 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 19 */ new Array( 32/* "+" */,63 , 33/* "-" */,64 ),
	/* State 20 */ new Array(  ),
	/* State 21 */ new Array( 35/* "%" */,65 , 34/* "/" */,66 , 36/* "*" */,67 ),
	/* State 22 */ new Array(  ),
	/* State 23 */ new Array(  ),
	/* State 24 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 25 */ new Array(  ),
	/* State 26 */ new Array( 38/* "(" */,69 ),
	/* State 27 */ new Array( 46/* "Identifier" */,72 ),
	/* State 28 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 29 */ new Array(  ),
	/* State 30 */ new Array(  ),
	/* State 31 */ new Array(  ),
	/* State 32 */ new Array(  ),
	/* State 33 */ new Array( 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 34 */ new Array( 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 35 */ new Array(  ),
	/* State 36 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 , 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 37 */ new Array( 44/* "." */,78 , 38/* "(" */,59 , 16/* "[" */,79 , 37/* "^" */,61 ),
	/* State 38 */ new Array(  ),
	/* State 39 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 , 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 40 */ new Array( 5/* "WHILE" */,81 ),
	/* State 41 */ new Array( 46/* "Identifier" */,17 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 42 */ new Array( 20/* ";" */,84 ),
	/* State 43 */ new Array(  ),
	/* State 44 */ new Array(  ),
	/* State 45 */ new Array(  ),
	/* State 46 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 47 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 48 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 49 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 50 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 51 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 52 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 53 */ new Array(  ),
	/* State 54 */ new Array( 19/* "}" */,92 , 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 55 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 56 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 57 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 58 */ new Array( 46/* "Identifier" */,97 ),
	/* State 59 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 60 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 61 */ new Array( 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 62 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 63 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 64 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 65 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 66 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 67 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 68 */ new Array( 39/* ")" */,106 , 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 ),
	/* State 69 */ new Array( 46/* "Identifier" */,108 ),
	/* State 70 */ new Array( 15/* ">>" */,109 , 40/* "," */,110 ),
	/* State 71 */ new Array(  ),
	/* State 72 */ new Array( 42/* ":" */,111 ),
	/* State 73 */ new Array( 17/* "]" */,112 , 40/* "," */,113 ),
	/* State 74 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 ),
	/* State 75 */ new Array(  ),
	/* State 76 */ new Array(  ),
	/* State 77 */ new Array( 4/* "ELSE" */,114 ),
	/* State 78 */ new Array( 46/* "Identifier" */,115 ),
	/* State 79 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 80 */ new Array(  ),
	/* State 81 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 82 */ new Array( 20/* ";" */,118 ),
	/* State 83 */ new Array( 44/* "." */,58 , 38/* "(" */,59 , 16/* "[" */,60 ),
	/* State 84 */ new Array(  ),
	/* State 85 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 86 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 87 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 88 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 89 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 90 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 91 */ new Array( 30/* "&&" */,56 , 29/* "||" */,57 ),
	/* State 92 */ new Array(  ),
	/* State 93 */ new Array(  ),
	/* State 94 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 ),
	/* State 95 */ new Array( 32/* "+" */,63 , 33/* "-" */,64 ),
	/* State 96 */ new Array( 32/* "+" */,63 , 33/* "-" */,64 ),
	/* State 97 */ new Array( 21/* "=" */,-30 ),
	/* State 98 */ new Array( 39/* ")" */,119 , 40/* "," */,113 ),
	/* State 99 */ new Array( 17/* "]" */,120 , 32/* "+" */,63 , 33/* "-" */,64 ),
	/* State 100 */ new Array(  ),
	/* State 101 */ new Array( 35/* "%" */,65 , 34/* "/" */,66 , 36/* "*" */,67 ),
	/* State 102 */ new Array( 35/* "%" */,65 , 34/* "/" */,66 , 36/* "*" */,67 ),
	/* State 103 */ new Array(  ),
	/* State 104 */ new Array(  ),
	/* State 105 */ new Array(  ),
	/* State 106 */ new Array(  ),
	/* State 107 */ new Array( 39/* ")" */,121 , 40/* "," */,122 ),
	/* State 108 */ new Array(  ),
	/* State 109 */ new Array(  ),
	/* State 110 */ new Array( 46/* "Identifier" */,72 ),
	/* State 111 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 112 */ new Array(  ),
	/* State 113 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 114 */ new Array( 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 115 */ new Array(  ),
	/* State 116 */ new Array( 17/* "]" */,127 , 32/* "+" */,63 , 33/* "-" */,64 ),
	/* State 117 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 , 20/* ";" */,128 ),
	/* State 118 */ new Array( 31/* "!" */,18 , 33/* "-" */,33 , 32/* "+" */,34 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 119 */ new Array( 16/* "[" */,131 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 120 */ new Array( 21/* "=" */,-31 ),
	/* State 121 */ new Array( 18/* "{" */,133 ),
	/* State 122 */ new Array( 46/* "Identifier" */,134 ),
	/* State 123 */ new Array(  ),
	/* State 124 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 ),
	/* State 125 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 ),
	/* State 126 */ new Array(  ),
	/* State 127 */ new Array(  ),
	/* State 128 */ new Array(  ),
	/* State 129 */ new Array( 24/* "~=" */,46 , 23/* "!=" */,47 , 26/* ">=" */,48 , 25/* "<=" */,49 , 27/* ">" */,50 , 28/* "<" */,51 , 22/* "==" */,52 , 20/* ";" */,135 ),
	/* State 130 */ new Array( 40/* "," */,136 ),
	/* State 131 */ new Array( 33/* "-" */,33 , 32/* "+" */,34 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 132 */ new Array( 44/* "." */,78 , 38/* "(" */,59 , 16/* "[" */,79 ),
	/* State 133 */ new Array(  ),
	/* State 134 */ new Array(  ),
	/* State 135 */ new Array( 46/* "Identifier" */,17 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 136 */ new Array( 48/* "Integer" */,22 , 49/* "Float" */,23 , 46/* "Identifier" */,38 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 ),
	/* State 137 */ new Array( 17/* "]" */,141 , 32/* "+" */,63 , 33/* "-" */,64 ),
	/* State 138 */ new Array( 19/* "}" */,142 , 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 139 */ new Array( 39/* ")" */,143 ),
	/* State 140 */ new Array( 44/* "." */,78 , 38/* "(" */,59 , 16/* "[" */,79 ),
	/* State 141 */ new Array(  ),
	/* State 142 */ new Array(  ),
	/* State 143 */ new Array( 3/* "IF" */,3 , 5/* "WHILE" */,4 , 6/* "DO" */,5 , 7/* "FOR" */,6 , 9/* "USE" */,7 , 11/* "DELETE" */,8 , 10/* "RETURN" */,9 , 18/* "{" */,12 , 20/* ";" */,13 , 46/* "Identifier" */,17 , 31/* "!" */,18 , 48/* "Integer" */,22 , 49/* "Float" */,23 , 38/* "(" */,24 , 47/* "String" */,25 , 8/* "FUNCTION" */,26 , 14/* "<<" */,27 , 16/* "[" */,28 , 12/* "TRUE" */,29 , 13/* "FALSE" */,30 , 45/* "NaN" */,31 , 33/* "-" */,33 , 32/* "+" */,34 ),
	/* State 144 */ new Array(  )
);

/* Goto-Table */
var goto_tab = new Array(
	/* State 0 */ new Array( 50/* Program */,1 ),
	/* State 1 */ new Array( 51/* Stmt */,2 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 2 */ new Array(  ),
	/* State 3 */ new Array( 54/* Expression */,36 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 4 */ new Array( 54/* Expression */,39 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 5 */ new Array( 51/* Stmt */,40 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 6 */ new Array(  ),
	/* State 7 */ new Array(  ),
	/* State 8 */ new Array(  ),
	/* State 9 */ new Array( 51/* Stmt */,44 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 10 */ new Array(  ),
	/* State 11 */ new Array(  ),
	/* State 12 */ new Array( 52/* Stmt_List */,54 ),
	/* State 13 */ new Array(  ),
	/* State 14 */ new Array(  ),
	/* State 15 */ new Array(  ),
	/* State 16 */ new Array(  ),
	/* State 17 */ new Array(  ),
	/* State 18 */ new Array( 63/* LogExp */,62 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 19 */ new Array(  ),
	/* State 20 */ new Array(  ),
	/* State 21 */ new Array(  ),
	/* State 22 */ new Array(  ),
	/* State 23 */ new Array(  ),
	/* State 24 */ new Array( 54/* Expression */,68 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 25 */ new Array(  ),
	/* State 26 */ new Array(  ),
	/* State 27 */ new Array( 55/* Prop_List */,70 , 56/* Prop */,71 ),
	/* State 28 */ new Array( 53/* Param_List */,73 , 54/* Expression */,74 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 29 */ new Array(  ),
	/* State 30 */ new Array(  ),
	/* State 31 */ new Array(  ),
	/* State 32 */ new Array(  ),
	/* State 33 */ new Array( 66/* ExpExp */,75 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 34 */ new Array( 66/* ExpExp */,76 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 35 */ new Array(  ),
	/* State 36 */ new Array( 51/* Stmt */,77 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 37 */ new Array(  ),
	/* State 38 */ new Array(  ),
	/* State 39 */ new Array( 51/* Stmt */,80 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 40 */ new Array(  ),
	/* State 41 */ new Array( 61/* Assign */,82 , 60/* Lhs */,14 , 59/* ExtValue */,83 , 67/* Value */,20 ),
	/* State 42 */ new Array(  ),
	/* State 43 */ new Array(  ),
	/* State 44 */ new Array(  ),
	/* State 45 */ new Array(  ),
	/* State 46 */ new Array( 63/* LogExp */,85 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 47 */ new Array( 63/* LogExp */,86 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 48 */ new Array( 63/* LogExp */,87 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 49 */ new Array( 63/* LogExp */,88 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 50 */ new Array( 63/* LogExp */,89 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 51 */ new Array( 63/* LogExp */,90 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 52 */ new Array( 63/* LogExp */,91 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 53 */ new Array(  ),
	/* State 54 */ new Array( 51/* Stmt */,93 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 55 */ new Array( 54/* Expression */,94 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 56 */ new Array( 62/* AddSubExp */,95 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 57 */ new Array( 62/* AddSubExp */,96 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 58 */ new Array(  ),
	/* State 59 */ new Array( 53/* Param_List */,98 , 54/* Expression */,74 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 60 */ new Array( 62/* AddSubExp */,99 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 61 */ new Array( 66/* ExpExp */,100 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 62 */ new Array(  ),
	/* State 63 */ new Array( 64/* MulDivExp */,101 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 64 */ new Array( 64/* MulDivExp */,102 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 65 */ new Array( 65/* NegExp */,103 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 66 */ new Array( 65/* NegExp */,104 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 67 */ new Array( 65/* NegExp */,105 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 68 */ new Array(  ),
	/* State 69 */ new Array( 57/* Param_Def_List */,107 ),
	/* State 70 */ new Array(  ),
	/* State 71 */ new Array(  ),
	/* State 72 */ new Array(  ),
	/* State 73 */ new Array(  ),
	/* State 74 */ new Array(  ),
	/* State 75 */ new Array(  ),
	/* State 76 */ new Array(  ),
	/* State 77 */ new Array(  ),
	/* State 78 */ new Array(  ),
	/* State 79 */ new Array( 62/* AddSubExp */,116 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 80 */ new Array(  ),
	/* State 81 */ new Array( 54/* Expression */,117 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 82 */ new Array(  ),
	/* State 83 */ new Array(  ),
	/* State 84 */ new Array(  ),
	/* State 85 */ new Array(  ),
	/* State 86 */ new Array(  ),
	/* State 87 */ new Array(  ),
	/* State 88 */ new Array(  ),
	/* State 89 */ new Array(  ),
	/* State 90 */ new Array(  ),
	/* State 91 */ new Array(  ),
	/* State 92 */ new Array(  ),
	/* State 93 */ new Array(  ),
	/* State 94 */ new Array(  ),
	/* State 95 */ new Array(  ),
	/* State 96 */ new Array(  ),
	/* State 97 */ new Array(  ),
	/* State 98 */ new Array(  ),
	/* State 99 */ new Array(  ),
	/* State 100 */ new Array(  ),
	/* State 101 */ new Array(  ),
	/* State 102 */ new Array(  ),
	/* State 103 */ new Array(  ),
	/* State 104 */ new Array(  ),
	/* State 105 */ new Array(  ),
	/* State 106 */ new Array(  ),
	/* State 107 */ new Array(  ),
	/* State 108 */ new Array(  ),
	/* State 109 */ new Array(  ),
	/* State 110 */ new Array( 56/* Prop */,123 ),
	/* State 111 */ new Array( 54/* Expression */,124 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 112 */ new Array(  ),
	/* State 113 */ new Array( 54/* Expression */,125 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 114 */ new Array( 51/* Stmt */,126 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 115 */ new Array(  ),
	/* State 116 */ new Array(  ),
	/* State 117 */ new Array(  ),
	/* State 118 */ new Array( 54/* Expression */,129 , 63/* LogExp */,15 , 62/* AddSubExp */,19 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 119 */ new Array( 58/* Attr_List */,130 , 59/* ExtValue */,132 , 67/* Value */,20 ),
	/* State 120 */ new Array(  ),
	/* State 121 */ new Array(  ),
	/* State 122 */ new Array(  ),
	/* State 123 */ new Array(  ),
	/* State 124 */ new Array(  ),
	/* State 125 */ new Array(  ),
	/* State 126 */ new Array(  ),
	/* State 127 */ new Array(  ),
	/* State 128 */ new Array(  ),
	/* State 129 */ new Array(  ),
	/* State 130 */ new Array(  ),
	/* State 131 */ new Array( 53/* Param_List */,73 , 62/* AddSubExp */,137 , 64/* MulDivExp */,21 , 54/* Expression */,74 , 65/* NegExp */,32 , 63/* LogExp */,15 , 66/* ExpExp */,35 , 59/* ExtValue */,37 , 67/* Value */,20 ),
	/* State 132 */ new Array(  ),
	/* State 133 */ new Array( 52/* Stmt_List */,138 ),
	/* State 134 */ new Array(  ),
	/* State 135 */ new Array( 61/* Assign */,139 , 60/* Lhs */,14 , 59/* ExtValue */,83 , 67/* Value */,20 ),
	/* State 136 */ new Array( 59/* ExtValue */,140 , 67/* Value */,20 ),
	/* State 137 */ new Array(  ),
	/* State 138 */ new Array( 51/* Stmt */,93 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 139 */ new Array(  ),
	/* State 140 */ new Array(  ),
	/* State 141 */ new Array(  ),
	/* State 142 */ new Array(  ),
	/* State 143 */ new Array( 51/* Stmt */,144 , 61/* Assign */,10 , 54/* Expression */,11 , 60/* Lhs */,14 , 63/* LogExp */,15 , 59/* ExtValue */,16 , 62/* AddSubExp */,19 , 67/* Value */,20 , 64/* MulDivExp */,21 , 65/* NegExp */,32 , 66/* ExpExp */,35 ),
	/* State 144 */ new Array(  )
);

/* Default-Actions-Table */
var defact_tab = new Array(
	 /* State 0 */ 2 ,
	 /* State 1 */ 0 ,
	 /* State 2 */ 1 ,
	 /* State 3 */ -1 ,
	 /* State 4 */ -1 ,
	 /* State 5 */ -1 ,
	 /* State 6 */ -1 ,
	 /* State 7 */ -1 ,
	 /* State 8 */ -1 ,
	 /* State 9 */ -1 ,
	 /* State 10 */ -1 ,
	 /* State 11 */ -1 ,
	 /* State 12 */ 4 ,
	 /* State 13 */ 29 ,
	 /* State 14 */ -1 ,
	 /* State 15 */ 40 ,
	 /* State 16 */ 53 ,
	 /* State 17 */ 65 ,
	 /* State 18 */ -1 ,
	 /* State 19 */ 44 ,
	 /* State 20 */ 62 ,
	 /* State 21 */ 47 ,
	 /* State 22 */ 63 ,
	 /* State 23 */ 64 ,
	 /* State 24 */ -1 ,
	 /* State 25 */ 67 ,
	 /* State 26 */ -1 ,
	 /* State 27 */ 10 ,
	 /* State 28 */ 7 ,
	 /* State 29 */ 71 ,
	 /* State 30 */ 72 ,
	 /* State 31 */ 73 ,
	 /* State 32 */ 51 ,
	 /* State 33 */ -1 ,
	 /* State 34 */ -1 ,
	 /* State 35 */ 56 ,
	 /* State 36 */ -1 ,
	 /* State 37 */ 53 ,
	 /* State 38 */ 65 ,
	 /* State 39 */ -1 ,
	 /* State 40 */ -1 ,
	 /* State 41 */ -1 ,
	 /* State 42 */ -1 ,
	 /* State 43 */ 24 ,
	 /* State 44 */ 25 ,
	 /* State 45 */ 26 ,
	 /* State 46 */ -1 ,
	 /* State 47 */ -1 ,
	 /* State 48 */ -1 ,
	 /* State 49 */ -1 ,
	 /* State 50 */ -1 ,
	 /* State 51 */ -1 ,
	 /* State 52 */ -1 ,
	 /* State 53 */ 27 ,
	 /* State 54 */ -1 ,
	 /* State 55 */ -1 ,
	 /* State 56 */ -1 ,
	 /* State 57 */ -1 ,
	 /* State 58 */ -1 ,
	 /* State 59 */ 7 ,
	 /* State 60 */ -1 ,
	 /* State 61 */ -1 ,
	 /* State 62 */ 43 ,
	 /* State 63 */ -1 ,
	 /* State 64 */ -1 ,
	 /* State 65 */ -1 ,
	 /* State 66 */ -1 ,
	 /* State 67 */ -1 ,
	 /* State 68 */ -1 ,
	 /* State 69 */ 14 ,
	 /* State 70 */ -1 ,
	 /* State 71 */ 9 ,
	 /* State 72 */ -1 ,
	 /* State 73 */ -1 ,
	 /* State 74 */ 6 ,
	 /* State 75 */ 54 ,
	 /* State 76 */ 55 ,
	 /* State 77 */ 18 ,
	 /* State 78 */ -1 ,
	 /* State 79 */ -1 ,
	 /* State 80 */ 20 ,
	 /* State 81 */ -1 ,
	 /* State 82 */ -1 ,
	 /* State 83 */ -1 ,
	 /* State 84 */ 23 ,
	 /* State 85 */ 39 ,
	 /* State 86 */ 38 ,
	 /* State 87 */ 37 ,
	 /* State 88 */ 36 ,
	 /* State 89 */ 35 ,
	 /* State 90 */ 34 ,
	 /* State 91 */ 33 ,
	 /* State 92 */ 28 ,
	 /* State 93 */ 3 ,
	 /* State 94 */ 17 ,
	 /* State 95 */ 42 ,
	 /* State 96 */ 41 ,
	 /* State 97 */ 61 ,
	 /* State 98 */ -1 ,
	 /* State 99 */ -1 ,
	 /* State 100 */ 52 ,
	 /* State 101 */ 46 ,
	 /* State 102 */ 45 ,
	 /* State 103 */ 50 ,
	 /* State 104 */ 49 ,
	 /* State 105 */ 48 ,
	 /* State 106 */ 66 ,
	 /* State 107 */ -1 ,
	 /* State 108 */ 13 ,
	 /* State 109 */ 69 ,
	 /* State 110 */ -1 ,
	 /* State 111 */ -1 ,
	 /* State 112 */ 70 ,
	 /* State 113 */ -1 ,
	 /* State 114 */ -1 ,
	 /* State 115 */ 61 ,
	 /* State 116 */ -1 ,
	 /* State 117 */ -1 ,
	 /* State 118 */ -1 ,
	 /* State 119 */ 59 ,
	 /* State 120 */ 57 ,
	 /* State 121 */ -1 ,
	 /* State 122 */ -1 ,
	 /* State 123 */ 8 ,
	 /* State 124 */ 11 ,
	 /* State 125 */ 5 ,
	 /* State 126 */ 19 ,
	 /* State 127 */ 57 ,
	 /* State 128 */ 21 ,
	 /* State 129 */ -1 ,
	 /* State 130 */ 60 ,
	 /* State 131 */ 7 ,
	 /* State 132 */ 16 ,
	 /* State 133 */ 4 ,
	 /* State 134 */ 12 ,
	 /* State 135 */ -1 ,
	 /* State 136 */ -1 ,
	 /* State 137 */ 44 ,
	 /* State 138 */ -1 ,
	 /* State 139 */ -1 ,
	 /* State 140 */ 15 ,
	 /* State 141 */ 58 ,
	 /* State 142 */ 68 ,
	 /* State 143 */ -1 ,
	 /* State 144 */ 22 
);



/* Symbol labels */
var labels = new Array(
	"Program'" /* Non-terminal symbol */,
	"ERROR_RESYNC" /* Terminal symbol */,
	"WHITESPACE" /* Terminal symbol */,
	"IF" /* Terminal symbol */,
	"ELSE" /* Terminal symbol */,
	"WHILE" /* Terminal symbol */,
	"DO" /* Terminal symbol */,
	"FOR" /* Terminal symbol */,
	"FUNCTION" /* Terminal symbol */,
	"USE" /* Terminal symbol */,
	"RETURN" /* Terminal symbol */,
	"DELETE" /* Terminal symbol */,
	"TRUE" /* Terminal symbol */,
	"FALSE" /* Terminal symbol */,
	"<<" /* Terminal symbol */,
	">>" /* Terminal symbol */,
	"[" /* Terminal symbol */,
	"]" /* Terminal symbol */,
	"{" /* Terminal symbol */,
	"}" /* Terminal symbol */,
	";" /* Terminal symbol */,
	"=" /* Terminal symbol */,
	"==" /* Terminal symbol */,
	"!=" /* Terminal symbol */,
	"~=" /* Terminal symbol */,
	"<=" /* Terminal symbol */,
	">=" /* Terminal symbol */,
	">" /* Terminal symbol */,
	"<" /* Terminal symbol */,
	"||" /* Terminal symbol */,
	"&&" /* Terminal symbol */,
	"!" /* Terminal symbol */,
	"+" /* Terminal symbol */,
	"-" /* Terminal symbol */,
	"/" /* Terminal symbol */,
	"%" /* Terminal symbol */,
	"*" /* Terminal symbol */,
	"^" /* Terminal symbol */,
	"(" /* Terminal symbol */,
	")" /* Terminal symbol */,
	"," /* Terminal symbol */,
	"#" /* Terminal symbol */,
	":" /* Terminal symbol */,
	"|" /* Terminal symbol */,
	"." /* Terminal symbol */,
	"NaN" /* Terminal symbol */,
	"Identifier" /* Terminal symbol */,
	"String" /* Terminal symbol */,
	"Integer" /* Terminal symbol */,
	"Float" /* Terminal symbol */,
	"Program" /* Non-terminal symbol */,
	"Stmt" /* Non-terminal symbol */,
	"Stmt_List" /* Non-terminal symbol */,
	"Param_List" /* Non-terminal symbol */,
	"Expression" /* Non-terminal symbol */,
	"Prop_List" /* Non-terminal symbol */,
	"Prop" /* Non-terminal symbol */,
	"Param_Def_List" /* Non-terminal symbol */,
	"Attr_List" /* Non-terminal symbol */,
	"ExtValue" /* Non-terminal symbol */,
	"Lhs" /* Non-terminal symbol */,
	"Assign" /* Non-terminal symbol */,
	"AddSubExp" /* Non-terminal symbol */,
	"LogExp" /* Non-terminal symbol */,
	"MulDivExp" /* Non-terminal symbol */,
	"NegExp" /* Non-terminal symbol */,
	"ExpExp" /* Non-terminal symbol */,
	"Value" /* Non-terminal symbol */,
	"$" /* Terminal symbol */
);



        if( !err_off ) {
            err_off = [];
        }
        if( !err_la ) {
            err_la = [];
        }

        sstack.push(0);
        vstack.push(0);
    
        PCB.la = this._lex(PCB);
            
        while( true ) {
            PCB.act = 146;
            for( i = 0; i < act_tab[sstack[sstack.length-1]].length; i+=2 ) {
                if( act_tab[sstack[sstack.length-1]][i] == PCB.la ) {
                    PCB.act = act_tab[sstack[sstack.length-1]][i+1];
                    break;
                }
            }
        
            if( PCB.act == 146 ) {
                if( ( PCB.act = defact_tab[ sstack[sstack.length-1] ] ) < 0 )
                    PCB.act = 146;
                else
                    PCB.act *= -1;
            }

            //Parse error? Try to recover!
            if( PCB.act == 146 )
            {
                //Report errors only when error_step is 0, and this is not a
                //subsequent error from a previous parse
                if( PCB.error_step == 0 )
                {
                    err_cnt++;
                    err_off.push( {offset: PCB.offset - PCB.att.length, line: PCB.line} );
                    err_la.push([]);
                    for( i = 0; i < act_tab[sstack[sstack.length-1]].length; i+=2 )
                        err_la[err_la.length-1].push(
                                labels[act_tab[sstack[sstack.length-1]][i]] );
                }
            
                //Perform error recovery
                while( sstack.length > 1 && PCB.act == 146 )
                {
                    sstack.pop();
                    vstack.pop();
                
                    //Try to shift on error token
                    for( i = 0; i < act_tab[sstack[sstack.length-1]].length; i+=2 )
                    {
                        if( act_tab[sstack[sstack.length-1]][i] == 1 )
                        {
                            PCB.act = act_tab[sstack[sstack.length-1]][i+1];
                        
                            sstack.push( PCB.act );
                            vstack.push( '' );
                        
                            break;
                        }
                    }
                }
            
                //Is it better to leave the parser now?
                if( sstack.length > 1 && PCB.act != 146 )
                {
                    //Ok, now try to shift on the next tokens
                    while( PCB.la != 68 )
                    {
                        PCB.act = 146;
                    
                        for( i = 0; i < act_tab[sstack[sstack.length-1]].length; i+=2 )
                        {
                            if( act_tab[sstack[sstack.length-1]][i] == PCB.la )
                            {
                                PCB.act = act_tab[sstack[sstack.length-1]][i+1];
                                break;
                            }
                        }
                    
                        if( PCB.act != 146 )
                            break;
                        
                        while( ( PCB.la = this._lex( PCB ) ) < 0 )
                            PCB.offset++;
                    }
                    while( PCB.la != 68 && PCB.act == 146 ) {}
                }
            
                if( PCB.act == 146 || PCB.la == 68 )
                {
                    break;
                }

                //Try to parse the next three tokens successfully...
                PCB.error_step = 3;
            }

            //Shift
            if( PCB.act > 0 )
            {
                sstack.push( PCB.act );
                vstack.push( PCB.att );
            
                PCB.la = this._lex( PCB );
            
                //Successfull shift and right beyond error recovery?
                if( PCB.error_step > 0 )
                    PCB.error_step--;
            }
            //Reduce
            else
            {
                act = PCB.act * -1;
            
                rval = void( 0 );
            
switch( act )
{
	case 0:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 1:
	{
		 this.execute( vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 2:
	{
		rval = vstack[ vstack.length - 0 ];
	}
	break;
	case 3:
	{
		 rval = this.createNode('node_op', 'op_none', vstack[ vstack.length - 2 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 4:
	{
		rval = vstack[ vstack.length - 0 ];
	}
	break;
	case 5:
	{
		 rval = this.createNode('node_op', 'op_param', vstack[ vstack.length - 1 ], vstack[ vstack.length - 3 ] ); 
	}
	break;
	case 6:
	{
		 rval = this.createNode('node_op', 'op_param', vstack[ vstack.length - 1 ]); 
	}
	break;
	case 7:
	{
		rval = vstack[ vstack.length - 0 ];
	}
	break;
	case 8:
	{
		 rval = this.createNode('node_op', 'op_proplst', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 9:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 10:
	{
		rval = vstack[ vstack.length - 0 ];
	}
	break;
	case 11:
	{
		 rval = this.createNode('node_op', 'op_prop', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 12:
	{
		 rval = this.createNode('node_op', 'op_paramdef', vstack[ vstack.length - 1 ], vstack[ vstack.length - 3 ]); 
	}
	break;
	case 13:
	{
		 rval = this.createNode('node_op', 'op_paramdef', vstack[ vstack.length - 1 ]); 
	}
	break;
	case 14:
	{
		rval = vstack[ vstack.length - 0 ];
	}
	break;
	case 15:
	{
		 rval = this.createNode('node_op', 'op_param', vstack[ vstack.length - 1 ], vstack[ vstack.length - 3 ] ); 
	}
	break;
	case 16:
	{
		 rval = this.createNode('node_op', 'op_param', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 17:
	{
		 rval = this.createNode('node_op', 'op_assign', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 18:
	{
		 rval = this.createNode('node_op', 'op_if', vstack[ vstack.length - 2 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 19:
	{
		 rval = this.createNode('node_op', 'op_if_else', vstack[ vstack.length - 4 ], vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 20:
	{
		 rval = this.createNode('node_op', 'op_while', vstack[ vstack.length - 2 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 21:
	{
		 rval = this.createNode('node_op', 'op_do', vstack[ vstack.length - 4 ], vstack[ vstack.length - 2 ] ); 
	}
	break;
	case 22:
	{
		 rval = this.createNode('node_op', 'op_for', vstack[ vstack.length - 7 ], vstack[ vstack.length - 5 ], vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ]); 
	}
	break;
	case 23:
	{
		 rval = this.createNode('node_op', 'op_use', vstack[ vstack.length - 2 ] ); 
	}
	break;
	case 24:
	{
		 rval = this.createNode('node_op', 'op_delete', vstack[ vstack.length - 1 ]); 
	}
	break;
	case 25:
	{
		 rval = this.createNode('node_op', 'op_return', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 26:
	{
		rval = vstack[ vstack.length - 2 ];
	}
	break;
	case 27:
	{
		 rval = this.createNode('node_op', 'op_noassign', vstack[ vstack.length - 2 ] ); 
	}
	break;
	case 28:
	{
		 rval = vstack[ vstack.length - 2 ]; rval.needsBrackets = true; 
	}
	break;
	case 29:
	{
		 rval = this.createNode('node_op', 'op_none' ); 
	}
	break;
	case 30:
	{
		 rval = this.createNode('node_op', 'op_lhs', vstack[ vstack.length - 1 ], vstack[ vstack.length - 3 ], 'dot'); 
	}
	break;
	case 31:
	{
		 rval = this.createNode('node_op', 'op_lhs', vstack[ vstack.length - 2 ], vstack[ vstack.length - 4 ], 'bracket'); 
	}
	break;
	case 32:
	{
		 rval = this.createNode('node_op', 'op_lhs', vstack[ vstack.length - 1 ]); 
	}
	break;
	case 33:
	{
		 rval = this.createNode('node_op', 'op_equ', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 34:
	{
		 rval = this.createNode('node_op', 'op_lot', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 35:
	{
		 rval = this.createNode('node_op', 'op_grt', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 36:
	{
		 rval = this.createNode('node_op', 'op_loe', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 37:
	{
		 rval = this.createNode('node_op', 'op_gre', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 38:
	{
		 rval = this.createNode('node_op', 'op_neq', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 39:
	{
		 rval = this.createNode('node_op', 'op_approx', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 40:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 41:
	{
		 rval = this.createNode('node_op', 'op_or', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ]); 
	}
	break;
	case 42:
	{
		 rval = this.createNode('node_op', 'op_and', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ]); 
	}
	break;
	case 43:
	{
		 rval = this.createNode('node_op', 'op_not', vstack[ vstack.length - 1 ]); 
	}
	break;
	case 44:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 45:
	{
		 rval = this.createNode('node_op', 'op_sub', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 46:
	{
		 rval = this.createNode('node_op', 'op_add', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 47:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 48:
	{
		 rval = this.createNode('node_op', 'op_mul', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 49:
	{
		 rval = this.createNode('node_op', 'op_div', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 50:
	{
		 rval = this.createNode('node_op', 'op_mod', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 51:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 52:
	{
		 rval = this.createNode('node_op', 'op_exp', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 53:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 54:
	{
		 rval = this.createNode('node_op', 'op_neg', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 55:
	{
		 rval = vstack[ vstack.length - 1 ]; 
	}
	break;
	case 56:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 57:
	{
		 rval = this.createNode('node_op', 'op_extvalue', vstack[ vstack.length - 4 ], vstack[ vstack.length - 2 ]); 
	}
	break;
	case 58:
	{
		 rval = this.createNode('node_op', 'op_extvalue', this.createNode('node_op', 'op_execfun', vstack[ vstack.length - 7 ], vstack[ vstack.length - 5 ]), vstack[ vstack.length - 2 ]); 
	}
	break;
	case 59:
	{
		 rval = this.createNode('node_op', 'op_execfun', vstack[ vstack.length - 4 ], vstack[ vstack.length - 2 ]); 
	}
	break;
	case 60:
	{
		 rval = this.createNode('node_op', 'op_execfun', vstack[ vstack.length - 5 ], vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ], true); 
	}
	break;
	case 61:
	{
		 rval = this.createNode('node_op', 'op_property', vstack[ vstack.length - 3 ], vstack[ vstack.length - 1 ]); 
	}
	break;
	case 62:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 63:
	{
		 rval = this.createNode('node_const', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 64:
	{
		 rval = this.createNode('node_const', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 65:
	{
		 rval = this.createNode('node_var', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 66:
	{
		 rval = vstack[ vstack.length - 2 ]; 
	}
	break;
	case 67:
	{
		 rval = this.createNode('node_str', vstack[ vstack.length - 1 ]); 
	}
	break;
	case 68:
	{
		 rval = this.createNode('node_op', 'op_function', vstack[ vstack.length - 5 ], vstack[ vstack.length - 2 ]); 
	}
	break;
	case 69:
	{
		 rval = this.createNode('node_op', 'op_proplst_val', vstack[ vstack.length - 2 ]); 
	}
	break;
	case 70:
	{
		 rval = this.createNode('node_op', 'op_array', vstack[ vstack.length - 2 ]); 
	}
	break;
	case 71:
	{
		 rval = this.createNode('node_const_bool', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 72:
	{
		 rval = this.createNode('node_const_bool', vstack[ vstack.length - 1 ] ); 
	}
	break;
	case 73:
	{
		 rval = NaN; 
	}
	break;
}


            
                for( i = 0; i < pop_tab[act][1]; i++ )
                {
                    sstack.pop();
                    vstack.pop();
                }

                //Get goto-table entry
                PCB.act = 146;
                for( i = 0; i < goto_tab[sstack[sstack.length-1]].length; i+=2 )
                {
                    if( goto_tab[sstack[sstack.length-1]][i] == pop_tab[act][0] )
                    {
                        PCB.act = goto_tab[sstack[sstack.length-1]][i+1];
                        break;
                    }
                }
            
                //Goal symbol match?
                if( act == 0 ) //Don't use PCB.act here!
                    break;
                
                //...and push it!
                sstack.push( PCB.act );
                vstack.push( rval );
            }
        }

        return err_cnt;
    }

});






/*
    Copyright 2008-2011
         Matthias Ehmann,
         Michael Gerhaeuser,
         Carsten Miller,
         Bianca Valentin,
         Alfred Wassermann,
         Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @fileoverview The JXG.Dump namespace provides methods to save a board to javascript.
 */

/**
 * The JXG.Dump namespace provides classes and methods to save a board to javascript.
 * @namespace
 */
JXG.Dump = {

    /**
     * Adds markers to every element of the board
     * @param {JXG.Board} board
     * @param {Array|String} markers
     * @param {Array|%} values
     */
    addMarkers: function (board, markers, values) {
        var e, l, i;

        if (!JXG.isArray(markers)) {
            markers = [markers];
        }

        if (!JXG.isArray(values)) {
            values = [values];
        }

        l = Math.min(markers.length, values.length);

        markers.length = l;
        values.length = l;

        for (e in board.objects) {
            for (i = 0; i < l; i++) {
                board.objects[e][markers[i]] = values[i];
            }
        }
    },

    /**
     * Removes markers from every element on the board.
     * @param {JXG.Board} board
     * @param {Array|String} markers
     */
    deleteMarkers: function (board, markers) {
        var e, l, i;

        if (!JXG.isArray(markers)) {
            markers = [markers];
        }

        l = markers.length;

        markers.length = l;

        for (e in board.objects) {
            for (i = 0; i < l; i++) {
                delete board.objects[e][markers[i]];
            }
        }
    },

    /**
     * Stringifies a string, i.e. puts some quotation marks around <tt>s</tt> if it is of type string.
     * @param {%} s
     * @returns {String} " + s + "
     */
    str: function (s) {
        if (typeof s === 'string' && s.substr(0, 7) !== 'function') {
            s = '\'' + s + '\'';
        }

        return s;
    },

    /**
     * Eliminate default values given by {@link JXG.Options} from the attributes object.
     * @param {Object} instance Attribute object of the element
     * @param {Object} % Arbitrary number of objects <tt>instance</tt> will be compared to. Usually these are
     * sub-objects of the {@link JXG.Board#options} structure.
     * @returns {Object} Minimal attributes object
     */
    minimizeObject: function (instance) {
        var p, pl, copy = JXG.deepCopy(instance),
            defaults = [], i;

        for (i = 1; i < arguments.length; i++) {
            defaults.push(arguments[i]);
        }

        for (i = 0; i < defaults.length; i++) {
            for (p in defaults[i]) {
                pl = p.toLowerCase();

                if (typeof defaults[i][p] !== 'object' && defaults[i][p] == copy[pl]) {
                    delete copy[pl];
                }
            }
        }

        return copy;
    },

    /**
     * Prepare the attributes object for an element.
     * @param {JXG.Board} board
     * @param {JXG.GeometryElement} obj Geometry element which attributes object is generated
     * @returns {Object} An attributes object.
     */
    prepareAttributes: function (board, obj) {
        var a, s;

        a = this.minimizeObject(obj.getAttributes(), board.options[obj.elType], board.options.elements);

        for (s in obj.subs) {
            a[s] = this.minimizeObject(obj.subs[s].getAttributes(), board.options[obj.elType][s], board.options[obj.subs[s].elType], board.options.elements);
            a[s].id = obj.subs[s].id;
            a[s].name = obj.subs[s].name;
        }

        a.id = obj.id;
        a.name = obj.name;

        return a;
    },

    /**
     * Generate a save-able structure with all elements. This is used by {@link JXG.Dump#toJessie} and {@link JXG.Dump#toJavaScript}
     * to generate the script.
     * @param {JXG.Board} board
     * @returns {Array} An array with all metadata necessary to save the construction.
     */
    dump: function (board) {
        var e, obj, element, s,
            elementList = [], len = board.objectsList.length;

        this.addMarkers(board, 'dumped', false);

        for (e = 0; e < len; e++) {
            obj = board.objectsList[e];
            element = {};

            if (!obj.dumped && obj.dump) {
                element.type = obj.getType();
                element.parents = obj.getParents();

                if (element.type === 'point' && element.parents[0] == 1) {
                    element.parents = element.parents.slice(1);
                }

                for (s = 0; s < element.parents.length; s++) {
                    if (typeof element.parents[s] === 'string') {
                        element.parents[s] = '\'' + element.parents[s] + '\'';
                    }
                }

                element.attributes = this.prepareAttributes(board, obj);

                elementList.push(element);
            }
        }

        this.deleteMarkers(board, 'dumped');

        return elementList;
    },

    /**
     * Converts a JavaScript object into a JSAN (JessieScript Attribute Notation) string.
     * @param {Object} obj A JavaScript object, functions will be ignored.
     * @returns {String} The given object stored in a JSAN string.
     */
    toJSAN: function (obj) {
        var s, i;

        switch (typeof obj) {
            case 'object':
                if (obj) {
                    var list = [];
                    if (obj instanceof Array) {
                        for (i = 0; i < obj.length; i++) {
                            list.push(this.toJSAN(obj[i]));
                        }
                        return '[' + list.join(',') + ']';
                    } else {
                        for (var prop in obj) {
                            list.push(prop + ': ' + this.toJSAN(obj[prop]));
                        }
                        return '<<' + list.join(', ') + '>> ';
                    }
                } else {
                    return 'null';
                }
            case 'string':
                return '\'' + obj.replace(/(["'])/g, '\\$1') + '\'';
            case 'number':
            case 'boolean':
                return new String(obj);
            case 'null':
                return 'null';
        }
    },

    /**
     * Saves the construction in <tt>board</tt> to JessieScript.
     * @param {JXG.Board} board
     * @returns {String} JessieScript
     */
    toJessie: function (board) {
        var elements = this.dump(board),
            script = [], i;

        for (i = 0; i < elements.length; i++) {
            if (elements[i].attributes.name.length > 0) {
                script.push('// ' + elements[i].attributes.name);
            }

            script.push('s' + i + ' = ' + elements[i].type + '(' + elements[i].parents.join(', ') + ') ' + this.toJSAN(elements[i].attributes).replace(/\n/, '\\n') + ';');
            script.push('');
        }

        return script.join('\n');
    },

    /**
     * Saves the construction in <tt>board</tt> to JavaScript.
     * @param {JXG.Board} board
     * @returns {String} JavaScript
     */
    toJavaScript: function (board) {
        var elements = this.dump(board),
            script = [], i;

        for (i = 0; i < elements.length; i++) {
            script.push('board.create("' + elements[i].type + '", [' + elements[i].parents.join(', ') + '], ' + JXG.toJSON(elements[i].attributes) + ');');
        }

        return script.join('\n');
    }
};

/*    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/*jshint bitwise: false, curly: true, debug: false, eqeqeq: true, devel: false, evil: false,
  forin: false, immed: true, laxbreak: false, newcap: false, noarg: true, nonew: true, onevar: true,
   undef: true, white: true, sub: false*/
/*global JXG: true, AMprocessNode: true, MathJax: true, document: true */

/**
 * Uses SVG to implement the rendering methods defined in {@link JXG.AbstractRenderer}.
 * @class JXG.AbstractRenderer
 * @augments JXG.AbstractRenderer
 * @param {Node} container Reference to a DOM node containing the board.
 * @see JXG.AbstractRenderer
 */
JXG.SVGRenderer = function (container) {
    var i;

    // docstring in AbstractRenderer
    this.type = 'svg';

    /**
     * SVG root node
     * @type Node
     * @private
     */
    this.svgRoot = null;

    /**
     * @private
     */
    //this.suspendHandle = null;

    /**
     * The SVG Namespace used in JSXGraph.
     * @see http://www.w3.org/TR/SVG/
     * @type String
     * @default http://www.w3.org/2000/svg
     */
    this.svgNamespace = 'http://www.w3.org/2000/svg';

    /**
     * The xlink namespace. This is used for images.
     * @see http://www.w3.org/TR/xlink/
     * @type String
     * @default http://www.w3.org/1999/xlink
     */
    this.xlinkNamespace = 'http://www.w3.org/1999/xlink';

    // container is documented in AbstractRenderer
    this.container = container;

    // prepare the div container and the svg root node for use with JSXGraph
    this.container.style.MozUserSelect = 'none';

    this.container.style.overflow = 'hidden';
    if (this.container.style.position === '') {
        this.container.style.position = 'relative';
    }

    this.svgRoot = this.container.ownerDocument.createElementNS(this.svgNamespace, "svg");
    this.svgRoot.style.overflow = 'hidden';

    this.svgRoot.style.width = JXG.getStyle(this.container, 'width');
    this.svgRoot.style.height = JXG.getStyle(this.container, 'height');

    this.container.appendChild(this.svgRoot);

    /**
     * The <tt>defs</tt> element is a container element to reference reusable SVG elements.
     * @type Node
     * @see http://www.w3.org/TR/SVG/struct.html#DefsElement
     */
    this.defs = this.container.ownerDocument.createElementNS(this.svgNamespace, 'defs');
    this.svgRoot.appendChild(this.defs);

    /**
     * Filters are used to apply shadows.
     * @type Node
     * @see http://www.w3.org/TR/SVG/filters.html#FilterElement
     */
    this.filter = this.container.ownerDocument.createElementNS(this.svgNamespace, 'filter');
    this.filter.setAttributeNS(null, 'id', this.container.id + '_' + 'f1');
    this.filter.setAttributeNS(null, 'width', '300%');
    this.filter.setAttributeNS(null, 'height', '300%');
    this.filter.setAttributeNS(null, 'filterUnits', 'userSpaceOnUse');
    
    this.feOffset = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feOffset');
    this.feOffset.setAttributeNS(null, 'result', 'offOut');
    this.feOffset.setAttributeNS(null, 'in', 'SourceAlpha');
    this.feOffset.setAttributeNS(null, 'dx', '5');
    this.feOffset.setAttributeNS(null, 'dy', '5');
    this.filter.appendChild(this.feOffset);

    this.feGaussianBlur = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feGaussianBlur');
    this.feGaussianBlur.setAttributeNS(null, 'result', 'blurOut');
    this.feGaussianBlur.setAttributeNS(null, 'in', 'offOut');
    this.feGaussianBlur.setAttributeNS(null, 'stdDeviation', '3'); 
    this.filter.appendChild(this.feGaussianBlur);

    this.feBlend = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feBlend');
    this.feBlend.setAttributeNS(null, 'in', 'SourceGraphic');
    this.feBlend.setAttributeNS(null, 'in2', 'blurOut');
    this.feBlend.setAttributeNS(null, 'mode', 'normal');
    this.filter.appendChild(this.feBlend);

    this.defs.appendChild(this.filter);    
    
    /**
     * JSXGraph uses a layer system to sort the elements on the board. This puts certain types of elements in front
     * of other types of elements. For the order used see {@link JXG.Options.layer}. The number of layers is documented
     * there, too. The higher the number, the "more on top" are the elements on this layer.
     * @type Array
     */
    this.layer = [];
    for (i = 0; i < JXG.Options.layer.numlayers; i++) {
        this.layer[i] = this.container.ownerDocument.createElementNS(this.svgNamespace, 'g');
        this.svgRoot.appendChild(this.layer[i]);
    }

    /**
     * Defines dash patterns. Defined styles are: <ol>
     * <li value="-1"> 2px dash, 2px space</li>
     * <li> 5px dash, 5px space</li>
     * <li> 10px dash, 10px space</li>
     * <li> 20px dash, 20px space</li>
     * <li> 20px dash, 10px space, 10px dash, 10px dash</li>
     * <li> 20px dash, 5px space, 10px dash, 5px space</li></ol>
     * @type Array
     * @default ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5']
     * @see http://www.w3.org/TR/SVG/painting.html#StrokeProperties
     */
    this.dashArray = ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5'];
};

JXG.SVGRenderer.prototype = new JXG.AbstractRenderer();

JXG.extend(JXG.SVGRenderer.prototype, /** @lends JXG.SVGRenderer.prototype */ {

    /**
     * Creates an arrow DOM node. Arrows are displayed in SVG with a <em>marker</em> tag.
     * @private
     * @param {JXG.GeometryElement} element A JSXGraph element, preferably one that can have an arrow attached.
     * @param {String} [idAppendix=''] A string that is added to the node's id.
     * @returns {Node} Reference to the node added to the DOM.
     */
    _createArrowHead: function (element, idAppendix) {
        var id = element.id + 'Triangle',
            node2, node3;

        if (JXG.exists(idAppendix)) {
            id += idAppendix;
        }
        node2 = this.createPrim('marker', id);

        node2.setAttributeNS(null, 'viewBox', '0 0 10 6');
        node2.setAttributeNS(null, 'refY', '3');
        node2.setAttributeNS(null, 'markerUnits', 'userSpaceOnUse'); //'strokeWidth');
        node2.setAttributeNS(null, 'markerHeight', '12');
        node2.setAttributeNS(null, 'markerWidth', '10');
        node2.setAttributeNS(null, 'orient', 'auto');
        node2.setAttributeNS(null, 'stroke', JXG.evaluate(element.visProp.strokecolor));
        node2.setAttributeNS(null, 'stroke-opacity', JXG.evaluate(element.visProp.strokeopacity));
        node2.setAttributeNS(null, 'fill', JXG.evaluate(element.visProp.strokecolor));
        node2.setAttributeNS(null, 'fill-opacity', JXG.evaluate(element.visProp.strokeopacity));
        node3 = this.container.ownerDocument.createElementNS(this.svgNamespace, 'path');

        if (idAppendix === 'End') {
            node2.setAttributeNS(null, 'refX', '0');
            node3.setAttributeNS(null, 'd', 'M 0 3 L 10 6 L 10 0 z');
        } else {
            node2.setAttributeNS(null, 'refX', '10');
            node3.setAttributeNS(null, 'd', 'M 0 0 L 10 3 L 0 6 z');
        }
        node2.appendChild(node3);
        return node2;
    },

    /**
     * Updates an arrow DOM node.
     * @param {Node} node The arrow node.
     * @param {String} color Color value in a HTML compatible format, e.g. <tt>#00ff00</tt> or <tt>green</tt> for green.
     * @param {Number} opacity
     */
    _setArrowAtts: function (node, color, opacity, width) {
        if (node) {
            node.setAttributeNS(null, 'stroke', color);
            node.setAttributeNS(null, 'stroke-opacity', opacity);
            node.setAttributeNS(null, 'fill', color);
            node.setAttributeNS(null, 'fill-opacity', opacity);
            node.setAttributeNS(null, 'stroke-width', width);
        }
    },

    /* ******************************** *
     *  This renderer does not need to
     *  override draw/update* methods
     *  since it provides draw/update*Prim
     *  methods except for some cases like
     *  internal texts or images.
     * ******************************** */

    /* **************************
     *    Lines
     * **************************/

    // documented in AbstractRenderer
    updateTicks: function (axis, dxMaj, dyMaj, dxMin, dyMin, minStyle, majStyle) {
        var tickStr = '',
            i, c, node,
            x, y, 
            len = axis.ticks.length;

        for (i = 0; i < len; i++) {
            c = axis.ticks[i];
            x = c[0];
            y = c[1];
            if (typeof x[0] != 'undefined' && typeof x[1] != 'undefined') {
                tickStr += "M " + (x[0]) + " " + (y[0]) + " L " + (x[1]) + " " + (y[1]) + " ";
            }
        }
        // Labels
        for (i = 0; i < len; i++) {
            c = axis.ticks[i].scrCoords;
            if (axis.ticks[i].major 
                && (axis.board.needsFullUpdate || axis.needsRegularUpdate) 
                && axis.labels[i] 
                && axis.labels[i].visProp.visible) {
                    this.updateText(axis.labels[i]);
            } 
        }
        node = this.getElementById(axis.id);
        if (!JXG.exists(node)) {
            node = this.createPrim('path', axis.id);
            this.appendChildPrim(node, axis.visProp.layer);
            this.appendNodesToElement(axis, 'path');
        }
        node.setAttributeNS(null, 'stroke', axis.visProp.strokecolor);
        node.setAttributeNS(null, 'stroke-opacity', axis.visProp.strokeopacity);
        node.setAttributeNS(null, 'stroke-width', axis.visProp.strokewidth);
        this.updatePathPrim(node, tickStr, axis.board);
    },

    /* **************************
     *    Text related stuff
     * **************************/

    // already documented in JXG.AbstractRenderer
    displayCopyright: function (str, fontsize) {
        var node = this.createPrim('text', 'licenseText'),
            t;
        node.setAttributeNS(null, 'x', '20px');
        node.setAttributeNS(null, 'y', (2 + fontsize) + 'px');
        node.setAttributeNS(null, "style", "font-family:Arial,Helvetica,sans-serif; font-size:" + fontsize + "px; fill:#356AA0;  opacity:0.3;");
        t = document.createTextNode(str);
        node.appendChild(t);
        this.appendChildPrim(node, 0);
    },

    // already documented in JXG.AbstractRenderer
    drawInternalText: function (el) {
        var node = this.createPrim('text', el.id);

        node.setAttributeNS(null, "class", el.visProp.cssclass);
        //node.setAttributeNS(null, "style", "alignment-baseline:middle"); // Not yet supported by Firefox
        el.rendNodeText = document.createTextNode('');
        node.appendChild(el.rendNodeText);
        this.appendChildPrim(node,  el.visProp.layer);

        return node;
    },

    // already documented in JXG.AbstractRenderer
    updateInternalText: function (el) {
        var content = el.plaintext;

        // el.rendNode.setAttributeNS(null, "class", el.visProp.cssclass);
        if (!isNaN(el.coords.scrCoords[1]+el.coords.scrCoords[2])) {
            el.rendNode.setAttributeNS(null, 'x', el.coords.scrCoords[1] + 'px');
            el.rendNode.setAttributeNS(null, 'y', (el.coords.scrCoords[2] + this.vOffsetText*0.5) + 'px');
            if (el.visProp.anchorx === 'right') {
                el.rendNode.setAttributeNS(null, 'text-anchor', 'end');
            } else if (el.visProp.anchorx === 'middle') {
                el.rendNode.setAttributeNS(null, 'text-anchor', 'middle');
            }
            if (el.visProp.anchory === 'top') {
                el.rendNode.setAttributeNS(null, 'dominant-baseline', 'text-before-edge');
            } else if (el.visProp.anchory === 'middle') {
                el.rendNode.setAttributeNS(null, 'dominant-baseline', 'middle');
            }
        }
        if (el.htmlStr !== content) {
            el.rendNodeText.data = content;
            el.htmlStr = content;
        }
        this.transformImage(el, el.transformations);
    },
    
     /**
     * Set color and opacity of internal texts. 
     * SVG needs its own version.
     * @private
     * @see JXG.AbstractRenderer#updateTextStyle
     * @see JXG.AbstractRenderer#updateInternalTextStyle
     */
    updateInternalTextStyle: function(element, strokeColor, strokeOpacity) {
        this.setObjectFillColor(element, strokeColor, strokeOpacity);        
    },
	
    /* **************************
     *    Image related stuff
     * **************************/

    // already documented in JXG.AbstractRenderer
    drawImage: function (el) {
        var node = this.createPrim('image', el.id);

        node.setAttributeNS(null, 'preserveAspectRatio', 'none');
        this.appendChildPrim(node, el.visProp.layer);
        el.rendNode = node;

        this.updateImage(el);
    },

    // already documented in JXG.AbstractRenderer
    transformImage: function (el, t) {
        var node = el.rendNode, m,
            str = "",
            s, len = t.length;

        if (len > 0) {
            m = this.joinTransforms(el, t);
            s = [m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]].join(',');
            str += ' matrix(' + s + ') ';
            node.setAttributeNS(null, 'transform', str);
        }
    },

    // already documented in JXG.AbstractRenderer
    updateImageURL: function (el) {
        var url = JXG.evaluate(el.url);
        el.rendNode.setAttributeNS(this.xlinkNamespace, 'xlink:href', url);
    },

    // already documented in JXG.AbstractRenderer
    updateImageStyle: function(el, doHighlight) { 
        var css = (doHighlight) ? el.visProp.highlightcssclass : el.visProp.cssclass;
         
        el.rendNode.setAttributeNS(null, 'class', css);
    },

    /* **************************
     * Render primitive objects
     * **************************/

    // already documented in JXG.AbstractRenderer
    appendChildPrim: function (node, level) {
        if (!JXG.exists(level)) { // trace nodes have level not set
            level = 0;
        } else if (level >= JXG.Options.layer.numlayers) {
            level = JXG.Options.layer.numlayers - 1;
        }
        this.layer[level].appendChild(node);
    },

    // already documented in JXG.AbstractRenderer
    appendNodesToElement: function (element) {
        element.rendNode = this.getElementById(element.id);
    },

    // already documented in JXG.AbstractRenderer
    createPrim: function (type, id) {
        var node = this.container.ownerDocument.createElementNS(this.svgNamespace, type);
        node.setAttributeNS(null, 'id', this.container.id + '_' + id);
        node.style.position = 'absolute';
        if (type === 'path') {
            node.setAttributeNS(null, 'stroke-linecap', 'butt');
            node.setAttributeNS(null, 'stroke-linejoin', 'round');
        }
        return node;
    },

    // already documented in JXG.AbstractRenderer
    remove: function (shape) {
        if (JXG.exists(shape) && JXG.exists(shape.parentNode)) {
            shape.parentNode.removeChild(shape);
        }
    },

    // already documented in JXG.AbstractRenderer
    makeArrows: function (el) {
        var node2;

        if (el.visPropOld.firstarrow === el.visProp.firstarrow && el.visPropOld.lastarrow === el.visProp.lastarrow) {
            return;
        }

        if (el.visProp.firstarrow) {
            node2 = el.rendNodeTriangleStart;
            if (!JXG.exists(node2)) {
                node2 = this._createArrowHead(el, 'End');
                this.defs.appendChild(node2);
                el.rendNodeTriangleStart = node2;
                el.rendNode.setAttributeNS(null, 'marker-start', 'url(#' + this.container.id + '_' + el.id + 'TriangleEnd)');
            } else {
                this.defs.appendChild(node2);
            }
        } else {
            node2 = el.rendNodeTriangleStart;
            if (JXG.exists(node2)) {
                this.remove(node2);
            }
        }
        if (el.visProp.lastarrow) {
            node2 = el.rendNodeTriangleEnd;
            if (!JXG.exists(node2)) {
                node2 = this._createArrowHead(el, 'Start');
                this.defs.appendChild(node2);
                el.rendNodeTriangleEnd = node2;
                el.rendNode.setAttributeNS(null, 'marker-end', 'url(#' + this.container.id + '_' + el.id + 'TriangleStart)');
            } else {
                this.defs.appendChild(node2);
            }
        } else {
            node2 = el.rendNodeTriangleEnd;
            if (JXG.exists(node2)) {
                this.remove(node2);
            }
        }
        el.visPropOld.firstarrow = el.visProp.firstarrow;
        el.visPropOld.lastarrow = el.visProp.lastarrow;
    },

    // already documented in JXG.AbstractRenderer
    updateEllipsePrim: function (node, x, y, rx, ry) {
        node.setAttributeNS(null, 'cx', x);
        node.setAttributeNS(null, 'cy', y);
        node.setAttributeNS(null, 'rx', Math.abs(rx));
        node.setAttributeNS(null, 'ry', Math.abs(ry));
    },

    // already documented in JXG.AbstractRenderer
    updateLinePrim: function (node, p1x, p1y, p2x, p2y) {
        if (!isNaN(p1x+p1y+p2x+p2y)) {
            node.setAttributeNS(null, 'x1', p1x);
            node.setAttributeNS(null, 'y1', p1y);
            node.setAttributeNS(null, 'x2', p2x);
            node.setAttributeNS(null, 'y2', p2y);
        }
    },

    // already documented in JXG.AbstractRenderer
    updatePathPrim: function (node, pointString) {
        if (pointString == '') {
            pointString = 'M 0 0';
        }
        node.setAttributeNS(null, 'd', pointString);
    },

    // already documented in JXG.AbstractRenderer
    updatePathStringPoint: function (el, size, type) {
        var s = '',
            scr = el.coords.scrCoords,
            sqrt32 = size * Math.sqrt(3) * 0.5,
            s05 = size * 0.5;

        if (type === 'x') {
            s = ' M ' + (scr[1] - size) + ' ' + (scr[2] - size) +
                ' L ' + (scr[1] + size) + ' ' + (scr[2] + size) +
                ' M ' + (scr[1] + size) + ' ' + (scr[2] - size) +
                ' L ' + (scr[1] - size) + ' ' + (scr[2] + size);
        } else if (type === '+') {
            s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) +
                ' L ' + (scr[1] + size) + ' ' + (scr[2]) +
                ' M ' + (scr[1])        + ' ' + (scr[2] - size) +
                ' L ' + (scr[1])        + ' ' + (scr[2] + size);
        } else if (type === '<>') {
            s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) +
                ' L ' + (scr[1])        + ' ' + (scr[2] + size) +
                ' L ' + (scr[1] + size) + ' ' + (scr[2]) +
                ' L ' + (scr[1])        + ' ' + (scr[2] - size) + ' Z ';
        } else if (type === '^') {
            s = ' M ' + (scr[1])          + ' ' + (scr[2] - size) +
                ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] + s05) +
                ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] + s05) +
                ' Z ';  // close path
        } else if (type === 'v') {
            s = ' M ' + (scr[1])          + ' ' + (scr[2] + size) +
                ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] - s05) +
                ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] - s05) +
                ' Z ';
        } else if (type === '>') {
            s = ' M ' + (scr[1] + size) + ' ' + (scr[2]) +
                ' L ' + (scr[1] - s05)  + ' ' + (scr[2] - sqrt32) +
                ' L ' + (scr[1] - s05)  + ' ' + (scr[2] + sqrt32) +
                ' Z ';
        } else if (type === '<') {
            s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) +
                ' L ' + (scr[1] + s05)  + ' ' + (scr[2] - sqrt32) +
                ' L ' + (scr[1] + s05)  + ' ' + (scr[2] + sqrt32) +
                ' Z ';
        }
        return s;
    },

    // already documented in JXG.AbstractRenderer
    updatePathStringPrim: function (el) {
        var symbm = ' M ',
            symbl = ' L ',
            symbc = ' C ', 
            nextSymb = symbm,
            maxSize = 5000.0,
            pStr = '',
            i, scr,
            isNotPlot = (el.visProp.curvetype !== 'plot'),
            len;

        if (el.numberPoints <= 0) {
            return '';
        }
        len = Math.min(el.points.length, el.numberPoints);

        if (el.bezierDegree == 1) {
            if (isNotPlot && el.board.options.curve.RDPsmoothing) {
                el.points = JXG.Math.Numerics.RamerDouglasPeuker(el.points, 0.5);
            }

            for (i = 0; i < len; i++) {
                scr = el.points[i].scrCoords;
                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    // Chrome has problems with values being too far away.
                    if (scr[1] > maxSize) {
                        scr[1] = maxSize;
                    } else if (scr[1] < -maxSize) {
                        scr[1] = -maxSize;
                    }

                    if (scr[2] > maxSize) {
                        scr[2] = maxSize;
                    } else if (scr[2] < -maxSize) {
                        scr[2] = -maxSize;
                    }
                    // Attention: first coordinate may be inaccurate if far way
                    //pStr += [nextSymb, scr[1], ' ', scr[2]].join('');
                    pStr += nextSymb + scr[1] + ' ' + scr[2];   // Seems to be faster on now (webkit and firefox)
                    nextSymb = symbl;
                }
            }
        } else if (el.bezierDegree==3) {
            i = 0;
            while (i < len) {
                scr = el.points[i].scrCoords;
                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    pStr += nextSymb + scr[1] + ' ' + scr[2];   
                    if (nextSymb==symbc){
                        i++;
                        scr = el.points[i].scrCoords;
                        pStr += ' ' + scr[1] + ' ' + scr[2];   
                        i++;
                        scr = el.points[i].scrCoords;
                        pStr += ' ' + scr[1] + ' ' + scr[2];   
                    }
                    nextSymb = symbc;
                }
                i++;
            }
        }
        return pStr;
    },

    // already documented in JXG.AbstractRenderer
    updatePathStringBezierPrim: function (el) {
        var symbm = ' M ',
            symbl = ' C ',
            nextSymb = symbm,
            maxSize = 5000.0,
            pStr = '',
            i, j, scr,
            lx, ly, f = el.visProp.strokewidth, 
            isNoPlot = (el.visProp.curvetype !== 'plot'),
            len;

        if (el.numberPoints <= 0) {
            return '';
        }

        if (isNoPlot && el.board.options.curve.RDPsmoothing) {
            el.points = JXG.Math.Numerics.RamerDouglasPeuker(el.points, 0.5);
        }

        len = Math.min(el.points.length, el.numberPoints);
        for (j=1; j<3; j++) {
            nextSymb = symbm;
            for (i = 0; i < len; i++) {
                scr = el.points[i].scrCoords;
                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    // Chrome has problems with values being too far away.
                    if (scr[1] > maxSize) {
                        scr[1] = maxSize;
                    } else if (scr[1] < -maxSize) {
                        scr[1] = -maxSize;
                    }

                    if (scr[2] > maxSize) {
                        scr[2] = maxSize;
                    } else if (scr[2] < -maxSize) {
                        scr[2] = -maxSize;
                    }
                
                    // Attention: first coordinate may be inaccurate if far way
                    if (nextSymb == symbm) {
                        pStr += [nextSymb, 
                            scr[1]+0*f*(2*j*Math.random()-j), ' ', 
                            scr[2]+0*f*(2*j*Math.random()-j)].join('');
                    } else {
                        pStr += [nextSymb, 
                            (lx + (scr[1]-lx)*0.333 + f*(2*j*Math.random()-j)), ' ',
                            (ly + (scr[2]-ly)*0.333 + f*(2*j*Math.random()-j)), ' ',
                            (lx + 2*(scr[1]-lx)*0.333 + f*(2*j*Math.random()-j)), ' ',
                            (ly + 2*(scr[2]-ly)*0.333 + f*(2*j*Math.random()-j)), ' ',
                            scr[1], ' ', scr[2]
                            ].join('');
                    }
                    nextSymb = symbl;
                    lx = scr[1];
                    ly = scr[2];
                }
            }
        }
        return pStr;
    },
        
    // already documented in JXG.AbstractRenderer
    updatePolygonPrim: function (node, el) {
        var pStr = '',
            scrCoords, i,
            len = el.vertices.length;

        node.setAttributeNS(null, 'stroke', 'none');
        for (i = 0; i < len - 1; i++) {
            if (el.vertices[i].isReal) {
                scrCoords = el.vertices[i].coords.scrCoords;
                pStr = pStr + scrCoords[1] + "," + scrCoords[2];
            } else {
                node.setAttributeNS(null, 'points', '');
                return;
            }
            if (i < len - 2) {
                pStr += " ";
            }
        }
        if (pStr.indexOf('NaN')==-1) 
            node.setAttributeNS(null, 'points', pStr);
    },

    // already documented in JXG.AbstractRenderer
    updateRectPrim: function (node, x, y, w, h) {
        node.setAttributeNS(null, 'x', x);
        node.setAttributeNS(null, 'y', y);
        node.setAttributeNS(null, 'width', w);
        node.setAttributeNS(null, 'height', h);
    },

    /* **************************
     *  Set Attributes
     * **************************/

    // documented in JXG.AbstractRenderer
    setPropertyPrim: function (node, key, val) {
        if (key === 'stroked') {
            return;
        }
        node.setAttributeNS(null, key, val);
    },

    // documented in JXG.AbstractRenderer
    show: function (el) {
        var node;

        if (el && el.rendNode) {
            node = el.rendNode;
            node.setAttributeNS(null, 'display', 'inline');
            node.style.visibility = "inherit";
        }
    },

    // documented in JXG.AbstractRenderer
    hide: function (el) {
        var node;

        if (el && el.rendNode) {
            node = el.rendNode;
            node.setAttributeNS(null, 'display', 'none');
            node.style.visibility = "hidden";
        }
    },

    // documented in JXG.AbstractRenderer
    setBuffering: function (el, type) {
        el.rendNode.setAttribute('buffered-rendering', type);
    },

    // documented in JXG.AbstractRenderer
    setDashStyle: function (el) {
        var dashStyle = el.visProp.dash, node = el.rendNode;
        
        if (el.visProp.dash > 0) {
            node.setAttributeNS(null, 'stroke-dasharray', this.dashArray[dashStyle - 1]);
        } else {
            if (node.hasAttributeNS(null, 'stroke-dasharray')) {
                node.removeAttributeNS(null, 'stroke-dasharray');
            }
        }
    },

    // documented in JXG.AbstractRenderer
    setGradient: function (el) {
        var fillNode = el.rendNode, col, op,
            node, node2, node3, x1, x2, y1, y2;

        op = JXG.evaluate(el.visProp.fillopacity);
        op = (op > 0) ? op : 0;

        col = JXG.evaluate(el.visProp.fillcolor);

        if (el.visProp.gradient === 'linear') {
            node = this.createPrim('linearGradient', el.id + '_gradient');
            x1 = '0%'; // TODO: get x1,x2,y1,y2 from el.visProp['angle']
            x2 = '100%';
            y1 = '0%';
            y2 = '0%'; //means 270 degrees

            node.setAttributeNS(null, 'x1', x1);
            node.setAttributeNS(null, 'x2', x2);
            node.setAttributeNS(null, 'y1', y1);
            node.setAttributeNS(null, 'y2', y2);
            node2 = this.createPrim('stop', el.id + '_gradient1');
            node2.setAttributeNS(null, 'offset', '0%');
            node2.setAttributeNS(null, 'style', 'stop-color:' + col + ';stop-opacity:' + op);
            node3 = this.createPrim('stop', el.id + '_gradient2');
            node3.setAttributeNS(null, 'offset', '100%');
            node3.setAttributeNS(null, 'style', 'stop-color:' + el.visProp.gradientsecondcolor + ';stop-opacity:' + el.visProp.gradientsecondopacity);
            node.appendChild(node2);
            node.appendChild(node3);
            this.defs.appendChild(node);
            fillNode.setAttributeNS(null, 'style', 'fill:url(#' + this.container.id + '_' + el.id + '_gradient)');
            el.gradNode1 = node2;
            el.gradNode2 = node3;
        } else if (el.visProp.gradient === 'radial') {
            node = this.createPrim('radialGradient', el.id + '_gradient');

            node.setAttributeNS(null, 'cx', '50%');
            node.setAttributeNS(null, 'cy', '50%');
            node.setAttributeNS(null, 'r', '50%');
            node.setAttributeNS(null, 'fx', el.visProp.gradientpositionx * 100 + '%');
            node.setAttributeNS(null, 'fy', el.visProp.gradientpositiony * 100 + '%');

            node2 = this.createPrim('stop', el.id + '_gradient1');
            node2.setAttributeNS(null, 'offset', '0%');
            node2.setAttributeNS(null, 'style', 'stop-color:' + el.visProp.gradientsecondcolor + ';stop-opacity:' + el.visProp.gradientsecondopacity);
            node3 = this.createPrim('stop', el.id + '_gradient2');
            node3.setAttributeNS(null, 'offset', '100%');
            node3.setAttributeNS(null, 'style', 'stop-color:' + col + ';stop-opacity:' + op);

            node.appendChild(node2);
            node.appendChild(node3);
            this.defs.appendChild(node);
            fillNode.setAttributeNS(null, 'style', 'fill:url(#' + this.container.id + '_' + el.id + '_gradient)');
            el.gradNode1 = node2;
            el.gradNode2 = node3;
        } else {
            fillNode.removeAttributeNS(null, 'style');
        }
    },

    // documented in JXG.AbstractRenderer
    updateGradient: function (el) {
        var node2 = el.gradNode1,
            node3 = el.gradNode2,
            col, op;

        if (!JXG.exists(node2) || !JXG.exists(node3)) {
            return;
        }

        op = JXG.evaluate(el.visProp.fillopacity);
        op = (op > 0) ? op : 0;

        col = JXG.evaluate(el.visProp.fillcolor);

        if (el.visProp.gradient === 'linear') {
            node2.setAttributeNS(null, 'style', 'stop-color:' + col + ';stop-opacity:' + op);
            node3.setAttributeNS(null, 'style', 'stop-color:' + el.visProp.gradientsecondcolor + ';stop-opacity:' + el.visProp.gradientsecondopacity);
        } else if (el.visProp.gradient === 'radial') {
            node2.setAttributeNS(null, 'style', 'stop-color:' + el.visProp.gradientsecondcolor + ';stop-opacity:' + el.visProp.gradientsecondopacity);
            node3.setAttributeNS(null, 'style', 'stop-color:' + col + ';stop-opacity:' + op);
        }
    },

    // documented in JXG.AbstractRenderer
    setObjectFillColor: function (el, color, opacity) {
        var node, rgba = JXG.evaluate(color), c, rgbo,
            o = JXG.evaluate(opacity), oo;

        o = (o > 0) ? o : 0;

        if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o) {
            return;
        }
        if (JXG.exists(rgba) && rgba !== false) {
            if (rgba.length!=9) {          // RGB, not RGBA
                c = rgba;
                oo = o;
            } else {                       // True RGBA, not RGB
                rgbo = JXG.rgba2rgbo(rgba);
                c = rgbo[0];
                oo = o*rgbo[1];
            }
            node = el.rendNode;
            if (c!='none') {               // problem in firefox 17
                node.setAttributeNS(null, 'fill', c);
            } else {
                oo = 0;
            }
            
            if (el.type === JXG.OBJECT_TYPE_IMAGE) {
                node.setAttributeNS(null, 'opacity', oo);
            } else {
                node.setAttributeNS(null, 'fill-opacity', oo);
            }
            if (JXG.exists(el.visProp.gradient)) {
                this.updateGradient(el);
            }
        }
        el.visPropOld.fillcolor = rgba;
        el.visPropOld.fillopacity = o;
    },

    // documented in JXG.AbstractRenderer
    setObjectStrokeColor: function (el, color, opacity) {
        var rgba = JXG.evaluate(color), c, rgbo,
            o = JXG.evaluate(opacity), oo,
            node;

        o = (o > 0) ? o : 0;

        if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) {
            return;
        }

        if (JXG.exists(rgba) && rgba !== false) {
            if (rgba.length!=9) {          // RGB, not RGBA
                c = rgba;
                oo = o;
            } else {                       // True RGBA, not RGB
                rgbo = JXG.rgba2rgbo(rgba);
                c = rgbo[0];
                oo = o*rgbo[1];
            }
            node = el.rendNode;
            if (el.type === JXG.OBJECT_TYPE_TEXT) {
                if (el.visProp.display === 'html') {
                    node.style.color = c;
					node.style.opacity = oo;
                } else {
                    node.setAttributeNS(null, "style", "fill:" + c);
                    node.setAttributeNS(null, "style", "fill-opacity:" + oo);
                }
            } else {
                node.setAttributeNS(null, 'stroke', c);
                node.setAttributeNS(null, 'stroke-opacity', oo);
            }
            if (el.type === JXG.OBJECT_TYPE_ARROW) {
                this._setArrowAtts(el.rendNodeTriangle, c, oo, el.visProp.strokewidth);
            } else if (el.elementClass === JXG.OBJECT_CLASS_CURVE || el.elementClass === JXG.OBJECT_CLASS_LINE) {
                if (el.visProp.firstarrow) {
                    this._setArrowAtts(el.rendNodeTriangleStart, c, oo, el.visProp.strokewidth);
                }
                if (el.visProp.lastarrow) {
                    this._setArrowAtts(el.rendNodeTriangleEnd, c, oo, el.visProp.strokewidth);
                }
            }
        }

        el.visPropOld.strokecolor = rgba;
        el.visPropOld.strokeopacity = o;
    },

    // documented in JXG.AbstractRenderer
    setObjectStrokeWidth: function (el, width) {
        var w = JXG.evaluate(width),
            node;

        if (el.visPropOld.strokewidth === w) {
            return;
        }

        node = el.rendNode;
        this.setPropertyPrim(node, 'stroked', 'true');
        if (JXG.exists(w)) {
            this.setPropertyPrim(node, 'stroke-width', w + 'px');

            if (el.type === JXG.OBJECT_TYPE_ARROW) {
                this._setArrowAtts(el.rendNodeTriangle, el.visProp.strokecolor, el.visProp.strokeopacity, w);
            } else if (el.elementClass === JXG.OBJECT_CLASS_CURVE || el.elementClass === JXG.OBJECT_CLASS_LINE) {
                if (el.visProp.firstarrow) {
                    this._setArrowAtts(el.rendNodeTriangleStart, el.visProp.strokecolor, el.visProp.strokeopacity, w);
                }
                if (el.visProp.lastarrow) {
                    this._setArrowAtts(el.rendNodeTriangleEnd, el.visProp.strokecolor, el.visProp.strokeopacity, w);
                }
            }
        }
        el.visPropOld.strokewidth = w;
    },

    // documented in JXG.AbstractRenderer
    setShadow: function (el) {
        if (el.visPropOld.shadow === el.visProp.shadow) {
            return;
        }

        if (JXG.exists(el.rendNode)) {
            if (el.visProp.shadow) {
                el.rendNode.setAttributeNS(null, 'filter', 'url(#' + this.container.id + '_' + 'f1)');
            } else {
                el.rendNode.removeAttributeNS(null, 'filter');
            }
        }
        el.visPropOld.shadow = el.visProp.shadow;
    },

    /* **************************
     * renderer control
     * **************************/
    
    // documented in JXG.AbstractRenderer
    suspendRedraw: function () {
        // It seems to be important for the Linux version of firefox
        //this.suspendHandle = this.svgRoot.suspendRedraw(10000);
    },

    // documented in JXG.AbstractRenderer
    unsuspendRedraw: function () {
        //this.svgRoot.unsuspendRedraw(this.suspendHandle);
        //this.svgRoot.unsuspendRedrawAll();
        //this.svgRoot.forceRedraw();
    },

    // document in AbstractRenderer
    resize: function (w, h) {
        this.svgRoot.style.width = parseFloat(w) + 'px';
        this.svgRoot.style.height = parseFloat(h) + 'px';
    }

});

/*    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/*jshint bitwise: false, curly: true, debug: false, eqeqeq: true, devel: false, evil: false,
  forin: false, immed: true, laxbreak: false, newcap: false, noarg: true, nonew: true, onevar: true,
   undef: true, white: false, sub: false*/
/*global JXG: true, AMprocessNode: true, MathJax: true, document: true */

/**
 * Uses VML to implement the rendering methods defined in {@link JXG.AbstractRenderer}.
 * @class JXG.AbstractRenderer
 * @augments JXG.AbstractRenderer
 * @param {Node} container Reference to a DOM node containing the board.
 * @see JXG.AbstractRenderer
 */
JXG.VMLRenderer = function (container) {
    this.type = 'vml';
    
    this.container = container;
    this.container.style.overflow = 'hidden';
    this.container.onselectstart = function () {
        return false;
    };
    
    this.resolution = 10; // Paths are drawn with a a resolution of this.resolution/pixel.
  
    // Add VML includes and namespace
    // Original: IE <=7
    //container.ownerDocument.createStyleSheet().addRule("v\\:*", "behavior: url(#default#VML);");
    if (!JXG.exists(JXG.vmlStylesheet)) {
        container.ownerDocument.namespaces.add("jxgvml", "urn:schemas-microsoft-com:vml");
        JXG.vmlStylesheet = this.container.ownerDocument.createStyleSheet();
        JXG.vmlStylesheet.addRule(".jxgvml", "behavior:url(#default#VML)");
    }

    try {
        !container.ownerDocument.namespaces.jxgvml && container.ownerDocument.namespaces.add("jxgvml", "urn:schemas-microsoft-com:vml");
        this.createNode = function (tagName) {
            return container.ownerDocument.createElement('<jxgvml:' + tagName + ' class="jxgvml">');
        };
    } catch (e) {
        this.createNode = function (tagName) {
            return container.ownerDocument.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="jxgvml">');
        };
    }

    // dash styles
    this.dashArray = ['Solid', '1 1', 'ShortDash', 'Dash', 'LongDash', 'ShortDashDot', 'LongDashDot'];    
};

JXG.VMLRenderer.prototype = new JXG.AbstractRenderer();

JXG.extend(JXG.VMLRenderer.prototype, /** @lends JXG.VMLRenderer */ {

    /**
     * Sets attribute <tt>key</tt> of node <tt>node</tt> to <tt>value</tt>.
     * @param {Node} node A DOM node.
     * @param {String} key Name of the attribute.
     * @param {String} val New value of the attribute.
     * @param {Boolean} [iFlag=false] If false, the attribute's name is case insensitive.
     */
    _setAttr: function (node, key, val, iFlag) {
        try {
            if (document.documentMode === 8) {
                node[key] = val;
            } else {
                node.setAttribute(key, val, iFlag);
            }
        } catch (e) {
            JXG.debug('_setAttr:'/*node.id*/ + ' ' + key + ' ' + val + '<br>\n');
        }
    },

    /* ******************************** *
     *  This renderer does not need to
     *  override draw/update* methods
     *  since it provides draw/update*Prim
     *  methods.
     * ******************************** */

    /* **************************
     *    Lines
     * **************************/

    // documented in AbstractRenderer
    updateTicks: function (axis, dxMaj, dyMaj, dxMin, dyMin) {
        var tickArr = [], i, len, c, ticks, r = this.resolution;

        len = axis.ticks.length;
        for (i = 0; i < len; i++) {
            c = axis.ticks[i];
            x = c[0];
            y = c[1];
            if (typeof x[0] != 'undefined' && typeof x[1] != 'undefined') {
                tickArr.push(
                    ' m ' + Math.round(r * x[0]) + ', ' + Math.round(r * y[0]) +
                    ' l ' + Math.round(r * x[1]) + ', ' + Math.round(r * y[1]) + ' '
                );
            }
        }
        // Labels
        for (i = 0; i < len; i++) {
            c = axis.ticks[i].scrCoords;
            if (axis.ticks[i].major 
                && (axis.board.needsFullUpdate || axis.needsRegularUpdate) 
                && axis.labels[i] 
                && axis.labels[i].visProp.visible) {
                    this.updateText(axis.labels[i]);
            } 
        }
         
        //ticks = this.getElementById(axis.id);
        if (!JXG.exists(axis)) {
            ticks = this.createPrim('path', axis.id);
            this.appendChildPrim(ticks, axis.visProp.layer);
            this.appendNodesToElement(axis, 'path');
        }
        this._setAttr(axis.rendNode, 'stroked', 'true');
        this._setAttr(axis.rendNode, 'strokecolor', axis.visProp.strokecolor, 1);
        this._setAttr(axis.rendNode, 'strokeweight', axis.visProp.strokewidth);
        this._setAttr(axis.rendNodeStroke, 'opacity', (axis.visProp.strokeopacity * 100) + '%');
        this.updatePathPrim(axis.rendNode, tickArr, axis.board);
    },

    /* **************************
     *    Text related stuff
     * **************************/

    // already documented in JXG.AbstractRenderer
    displayCopyright: function (str, fontsize) {
        var node, t;

        node = this.createNode('textbox');
        node.style.position = 'absolute';
        this._setAttr(node, 'id', this.container.id + '_' + 'licenseText');

        node.style.left = 20;
        node.style.top = 2;
        node.style.fontSize = fontsize;
        node.style.color = '#356AA0';
        node.style.fontFamily = 'Arial,Helvetica,sans-serif';
        this._setAttr(node, 'opacity', '30%');
        node.style.filter = 'alpha(opacity = 30)';

        t = document.createTextNode(str);
        node.appendChild(t);
        this.appendChildPrim(node, 0);
    },

    // documented in AbstractRenderer
    drawInternalText: function (el) {
        var node;
        node = this.createNode('textbox');
        node.style.position = 'absolute';
        /*
        if (document.documentMode === 8) {                 // IE 8
            node.setAttribute('class', el.visProp.cssclass);
        } else {
            node.setAttribute(document.all ? 'className' : 'class', el.visProp.cssclass);
        }
        */
        el.rendNodeText = document.createTextNode('');
        node.appendChild(el.rendNodeText);
        this.appendChildPrim(node, 9);
        return node;
    },

    // documented in AbstractRenderer
    updateInternalText: function (el) {
        var content = el.plaintext;
        /*
        if (document.documentMode === 8) {                 // IE 8
            el.rendNode.setAttribute('class', el.visProp.cssclass);
        } else {
            el.rendNode.setAttribute(document.all ? 'className' : 'class', el.visProp.cssclass);
        }
        */
        if (!isNaN(el.coords.scrCoords[1]+el.coords.scrCoords[2])) {
            if (el.visProp.anchorx === 'right') {
                el.rendNode.style.right = parseInt(el.board.canvasWidth - el.coords.scrCoords[1]) + 'px';
            } else if (el.visProp.anchorx === 'middle') {
                el.rendNode.style.left = parseInt(el.coords.scrCoords[1]-0.5*el.size[0]) + 'px';
            } else {
                el.rendNode.style.left = parseInt(el.coords.scrCoords[1]) + 'px';
            }
            el.rendNode.style.top = parseInt(el.coords.scrCoords[2] - el.visProp.fontsize + this.vOffsetText) + 'px';
            if (el.visProp.anchory === 'top') {
                el.rendNode.style.top = parseInt(el.coords.scrCoords[2] + this.vOffsetText) + 'px';
            } else if (el.visProp.anchory === 'middle') {
                el.rendNode.style.top = parseInt(el.coords.scrCoords[2] - 0.5*el.size[1] + this.vOffsetText) + 'px';
            } else {
                el.rendNode.style.top = parseInt(el.coords.scrCoords[2] - el.size[1] + this.vOffsetText) + 'px';
            }
 
        }
        
        if (el.htmlStr !== content) {
            el.rendNodeText.data = content;
            el.htmlStr = content;
        }

        this.transformImage(el, el.transformations);
    },

    /* **************************
     *    Image related stuff
     * **************************/

    // already documented in JXG.AbstractRenderer
    drawImage: function (el) {
        // IE 8: Bilder ueber data URIs werden bis 32kB unterstuetzt.
        var node;

        node = this.container.ownerDocument.createElement('img');
        node.style.position = 'absolute';
        this._setAttr(node, 'id', this.container.id + '_' + el.id);

        this.container.appendChild(node);
        this.appendChildPrim(node, el.visProp.layer);

        // Adding the rotation filter. This is always filter item 0:
        // node.filters.item(0), see transformImage
        //node.style.filter = node.style['-ms-filter'] = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand')";
        node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand')";
        el.rendNode = node;
        this.updateImage(el);
    },

    // already documented in JXG.AbstractRenderer
    transformImage: function (el, t) {
        var node = el.rendNode,
            m, p = [], s, len = t.length,
            maxX, maxY, minX, minY, i, nt;

        if (el.type === JXG.OBJECT_TYPE_TEXT) {
            el.updateSize();
        }
        if (len > 0) {
            nt = el.rendNode.style.filter.toString();
            if (!nt.match(/DXImageTransform/)) {
                node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') " + nt;
            }

            m = this.joinTransforms(el, t);
            p[0] = JXG.Math.matVecMult(m, el.coords.scrCoords);
            p[0][1] /= p[0][0];
            p[0][2] /= p[0][0];
            p[1] = JXG.Math.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2]]);
            p[1][1] /= p[1][0];
            p[1][2] /= p[1][0];
            p[2] = JXG.Math.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2] - el.size[1]]);
            p[2][1] /= p[2][0];
            p[2][2] /= p[2][0];
            p[3] = JXG.Math.matVecMult(m, [1, el.coords.scrCoords[1], el.coords.scrCoords[2] - el.size[1]]);
            p[3][1] /= p[3][0];
            p[3][2] /= p[3][0];
            maxX = p[0][1];
            minX = p[0][1];
            maxY = p[0][2];
            minY = p[0][2];
            for (i = 1; i < 4; i++) {
                maxX = Math.max(maxX, p[i][1]);
                minX = Math.min(minX, p[i][1]);
                maxY = Math.max(maxY, p[i][2]);
                minY = Math.min(minY, p[i][2]);
            }
            node.style.left = parseInt(minX) + 'px';
            node.style.top  = parseInt(minY) + 'px';

            node.filters.item(0).M11 = m[1][1];
            node.filters.item(0).M12 = m[1][2];
            node.filters.item(0).M21 = m[2][1];
            node.filters.item(0).M22 = m[2][2];
        }
    },

    // already documented in JXG.AbstractRenderer
    updateImageURL: function (el) {
        var url = JXG.evaluate(el.url);
        this._setAttr(el.rendNode, 'src', url);
    },

    /* **************************
     * Render primitive objects
     * **************************/

    // already documented in JXG.AbstractRenderer
    appendChildPrim: function (node, level) {
        if (!JXG.exists(level)) {  // For trace nodes
            level = 0;
        }
        node.style.zIndex = level;
        this.container.appendChild(node);
    },

    // already documented in JXG.AbstractRenderer
    appendNodesToElement: function (element, type) {
        if (type === 'shape' || type === 'path' || type === 'polygon') {
            element.rendNodePath = this.getElementById(element.id + '_path');
        }
        element.rendNodeFill = this.getElementById(element.id + '_fill');
        element.rendNodeStroke = this.getElementById(element.id + '_stroke');
        element.rendNodeShadow = this.getElementById(element.id + '_shadow');
        element.rendNode = this.getElementById(element.id);
    },

    // already documented in JXG.AbstractRenderer
    createPrim: function (type, id) {
        var node,
            fillNode = this.createNode('fill'),
            strokeNode = this.createNode('stroke'),
            shadowNode = this.createNode('shadow'),
            pathNode;

        this._setAttr(fillNode, 'id', this.container.id + '_' + id + '_fill');
        this._setAttr(strokeNode, 'id', this.container.id + '_' + id + '_stroke');
        this._setAttr(shadowNode, 'id', this.container.id + '_' + id + '_shadow');

        if (type === 'circle' || type === 'ellipse') {
            node = this.createNode('oval');
            node.appendChild(fillNode);
            node.appendChild(strokeNode);
            node.appendChild(shadowNode);
        } else if (type === 'polygon' || type === 'path' || type === 'shape' || type === 'line') {
            node = this.createNode('shape');
            node.appendChild(fillNode);
            node.appendChild(strokeNode);
            node.appendChild(shadowNode);
            pathNode = this.createNode('path');
            this._setAttr(pathNode, 'id', this.container.id + '_' + id + '_path');
            node.appendChild(pathNode);
        } else {
            node = this.createNode(type);
            node.appendChild(fillNode);
            node.appendChild(strokeNode);
            node.appendChild(shadowNode);
        }
        node.style.position = 'absolute';
        node.style.left = '0px';
        node.style.top = '0px';
        this._setAttr(node, 'id', this.container.id + '_' + id);

        return node;
    },

    // already documented in JXG.AbstractRenderer
    remove: function (node) {
        if (JXG.exists(node)) {
            node.removeNode(true);
        }
    },

    // already documented in JXG.AbstractRenderer
    makeArrows: function (el) {
        var nodeStroke;

        if (el.visPropOld.firstarrow === el.visProp.firstarrow && el.visPropOld.lastarrow === el.visProp.lastarrow) {
            return;
        }

        if (el.visProp.firstarrow) {
            nodeStroke = el.rendNodeStroke;
            this._setAttr(nodeStroke, 'startarrow', 'block');
            this._setAttr(nodeStroke, 'startarrowlength', 'long');
        } else {
            nodeStroke = el.rendNodeStroke;
            if (JXG.exists(nodeStroke)) {
                this._setAttr(nodeStroke, 'startarrow', 'none');
            }
        }

        if (el.visProp.lastarrow) {
            nodeStroke = el.rendNodeStroke;
            this._setAttr(nodeStroke, 'id', this.container.id + '_' + el.id + "stroke");
            this._setAttr(nodeStroke, 'endarrow', 'block');
            this._setAttr(nodeStroke, 'endarrowlength', 'long');
        } else {
            nodeStroke = el.rendNodeStroke;
            if (JXG.exists(nodeStroke)) {
                this._setAttr(nodeStroke, 'endarrow', 'none');
            }
        }
        el.visPropOld.firstarrow = el.visProp.firstarrow;
        el.visPropOld.lastarrow = el.visProp.lastarrow;
    },

    // already documented in JXG.AbstractRenderer
    updateEllipsePrim: function (node, x, y, rx, ry) {
        node.style.left = parseInt(x - rx) + 'px';
        node.style.top =  parseInt(y - ry) + 'px';
        node.style.width = parseInt(Math.abs(rx) * 2) + 'px';
        node.style.height = parseInt(Math.abs(ry) * 2) + 'px';
    },

    // already documented in JXG.AbstractRenderer
    updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) {
        var s, r = this.resolution;

        if (!isNaN(p1x+p1y+p2x+p2y)) {
            s = ['m ', parseInt(r * p1x), ', ', parseInt(r * p1y), ' l ', parseInt(r * p2x), ', ', parseInt(r * p2y)];
            this.updatePathPrim(node, s, board);
        }
    },

    // already documented in JXG.AbstractRenderer
    updatePathPrim: function (node, pointString, board) {
        var x = board.canvasWidth,
            y = board.canvasHeight;
        if (pointString.length <= 0) {
            pointString = ['m 0,0'];
        }
        node.style.width = x;
        node.style.height = y;
        this._setAttr(node, 'coordsize', [parseInt(this.resolution * x), parseInt(this.resolution * y)].join(','));
        this._setAttr(node, 'path', pointString.join(""));
    },

    // already documented in JXG.AbstractRenderer
    updatePathStringPoint: function (el, size, type) {
        var s = [],
            mround = Math.round,
            scr = el.coords.scrCoords,
            sqrt32 = size * Math.sqrt(3) * 0.5,
            s05 = size * 0.5,
            r = this.resolution;

        if (type === 'x') {
            s.push([
                ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] - size)),
                ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] + size)),
                ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] - size)),
                ' l ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] + size))
            ].join(''));
        }
        else if (type === '+') {
            s.push([
                ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])),
                ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])),
                ' m ', mround(r * (scr[1])),        ', ', mround(r * (scr[2] - size)),
                ' l ', mround(r * (scr[1])),        ', ', mround(r * (scr[2] + size))
            ].join(''));
        }
        else if (type === '<>') {
            
            s.push([
                ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])),
                ' l ', mround(r * (scr[1])),        ', ', mround(r * (scr[2] + size)),
                ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])),
                ' l ', mround(r * (scr[1])),        ', ', mround(r * (scr[2] - size)),
                ' x e '
            ].join(''));
        }
        else if (type === '^') {
            s.push([
                ' m ', mround(r * (scr[1])),          ', ', mround(r * (scr[2] - size)),
                ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] + s05)),
                ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] + s05)),
                ' x e '
            ].join(''));
        }
        else if (type === 'v') {
            s.push([
                ' m ', mround(r * (scr[1])),          ', ', mround(r * (scr[2] + size)),
                ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] - s05)),
                ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] - s05)),
                ' x e '
            ].join(''));
        }
        else if (type === '>') {
            s.push([
                ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])),
                ' l ', mround(r * (scr[1] - s05)),  ', ', mround(r * (scr[2] - sqrt32)),
                ' l ', mround(r * (scr[1] - s05)),  ', ', mround(r * (scr[2] + sqrt32)),
                ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2]))
            ].join(''));
        }
        else if (type === '<') {
            s.push([
                ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])),
                ' l ', mround(r * (scr[1] + s05)),  ', ', mround(r * (scr[2] - sqrt32)),
                ' l ', mround(r * (scr[1] + s05)),  ', ', mround(r * (scr[2] + sqrt32)),
                ' x e '
            ].join(''));
        }
        return s;
    },

    // already documented in JXG.AbstractRenderer
    updatePathStringPrim: function (el) {
        var pStr = [],
            i, scr,
            r = this.resolution,
            mround = Math.round,
            symbm = ' m ',
            symbl = ' l ',
            symbc = ' c ',
            nextSymb = symbm,
            isNotPlot = (el.visProp.curvetype !== 'plot'),
            len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html

        if (el.numberPoints <= 0) {
            return '';
        }
        len = Math.min(len, el.points.length);

        if (el.bezierDegree == 1) {
            if (isNotPlot && el.board.options.curve.RDPsmoothing) {
                el.points = JXG.Math.Numerics.RamerDouglasPeuker(el.points, 1.0);
            }

            for (i = 0; i < len; i++) {
                scr = el.points[i].scrCoords;
                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    // IE has problems with values  being too far away.
                    if (scr[1] > 20000.0) {
                        scr[1] = 20000.0;
                    } else if (scr[1] < -20000.0) {
                        scr[1] = -20000.0;
                    }

                    if (scr[2] > 20000.0) {
                        scr[2] = 20000.0;
                    } else if (scr[2] < -20000.0) {
                        scr[2] = -20000.0;
                    }

                    pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));
                    nextSymb = symbl;
                }
            }
        } else if (el.bezierDegree==3) {
            i = 0;
            while (i < len) {
                scr = el.points[i].scrCoords;
                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));
                    if (nextSymb==symbc){
                        i++;
                        scr = el.points[i].scrCoords;
                        pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));
                        i++;
                        scr = el.points[i].scrCoords;
                        pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));
                    }
                    nextSymb = symbc;
                }
                i++;
            }
        }
        pStr.push(' e');
        return pStr;
    },

    // already documented in JXG.AbstractRenderer
    updatePathStringBezierPrim: function (el) {
        var pStr = [],
            i, j, scr,
            lx, ly, f = el.visProp.strokewidth, 
            r = this.resolution,
            mround = Math.round,
            symbm = ' m ',
            symbl = ' c ',
            nextSymb = symbm,
            isNoPlot = (el.visProp.curvetype !== 'plot'),
            len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html

        if (el.numberPoints <= 0) {
            return '';
        }
        if (isNoPlot && el.board.options.curve.RDPsmoothing) {
            el.points = JXG.Math.Numerics.RamerDouglasPeuker(el.points, 1.0);
        }
        len = Math.min(len, el.points.length);

        for (j=1; j<3; j++) {
            nextSymb = symbm;
            for (i = 0; i < len; i++) {
                scr = el.points[i].scrCoords;
                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    // IE has problems with values  being too far away.
                    if (scr[1] > 20000.0) {
                        scr[1] = 20000.0;
                    } else if (scr[1] < -20000.0) {
                        scr[1] = -20000.0;
                    }
    
                    if (scr[2] > 20000.0) {
                        scr[2] = 20000.0;
                    } else if (scr[2] < -20000.0) {
                        scr[2] = -20000.0;
                    }
    
                    if (nextSymb == symbm) {
                        pStr.push([nextSymb, 
                            mround(r * (scr[1]+0*f*(2*j*Math.random()-j))), ' ', 
                            mround(r * (scr[2]+0*f*(2*j*Math.random()-j)))].join(''));
                    } else {
                        pStr.push([nextSymb, 
                            mround(r * (lx + (scr[1]-lx)*0.333 + f*(2*j*Math.random()-j))), ' ',
                            mround(r * (ly + (scr[2]-ly)*0.333 + f*(2*j*Math.random()-j))), ' ',
                            mround(r * (lx + 2*(scr[1]-lx)*0.333 + f*(2*j*Math.random()-j))), ' ',
                            mround(r * (ly + 2*(scr[2]-ly)*0.333 + f*(2*j*Math.random()-j))), ' ',
                            mround(r * scr[1]), ' ', 
                            mround(r * scr[2])
                            ].join(''));
                    }
                    nextSymb = symbl;
                    lx = scr[1];
                    ly = scr[2];
                }
            }
        }      
        pStr.push(' e');
        return pStr;
    },
    
    // already documented in JXG.AbstractRenderer
    updatePolygonPrim: function (node, el) {
        var i,
            len = el.vertices.length,
            r = this.resolution,
            scr,
            pStr = [];

        this._setAttr(node, 'stroked', 'false');

        scr = el.vertices[0].coords.scrCoords;
        if (isNaN(scr[1]+scr[2])) return;
        pStr.push(["m ", parseInt(r * scr[1]), ",", parseInt(r * scr[2]), " l "].join(''));

        for (i = 1; i < len - 1; i++) {
            if (el.vertices[i].isReal) {
                scr = el.vertices[i].coords.scrCoords;
                if (isNaN(scr[1]+scr[2])) return;
                pStr.push(parseInt(r * scr[1]) + "," + parseInt(r * scr[2]));
            } else {
                this.updatePathPrim(node, '', el.board);
                return;
            }
            if (i < len - 2) {
                    pStr.push(", ");
            }
        }
        pStr.push(" x e");
        this.updatePathPrim(node, pStr, el.board);
    },

    // already documented in JXG.AbstractRenderer
    updateRectPrim: function (node, x, y, w, h) {
        node.style.left = parseInt(x) + 'px';
        node.style.top = parseInt(y) + 'px';

        if (w >= 0) {
            node.style.width = w + 'px';
        }
        
        if (h >= 0) {
            node.style.height = h + 'px';
        }
    },

    /* **************************
     *  Set Attributes
     * **************************/

    // already documented in JXG.AbstractRenderer
    setPropertyPrim: function (node, key, val) {
        var keyVml = '',
            v;

        switch (key) {
            case 'stroke':
                keyVml = 'strokecolor';
                break;
            case 'stroke-width':
                keyVml = 'strokeweight';
                break;
            case 'stroke-dasharray':
                keyVml = 'dashstyle';
                break;
        }

        if (keyVml !== '') {
            v = JXG.evaluate(val);
            this._setAttr(node, keyVml, v);
        }
    },

    // already documented in JXG.AbstractRenderer
    show: function (el) {
        if (el && el.rendNode) {
            el.rendNode.style.visibility = "inherit";
        }
    },

    // already documented in JXG.AbstractRenderer
    hide: function (el) {
        if (el && el.rendNode) {
            el.rendNode.style.visibility = "hidden";
        }
    },

    // already documented in JXG.AbstractRenderer
    setDashStyle: function (el, visProp) {
        var node;
        if (visProp.dash >= 0) {
            node = el.rendNodeStroke;
            this._setAttr(node, 'dashstyle', this.dashArray[visProp.dash]);
        }
    },

    // already documented in JXG.AbstractRenderer
    setGradient: function (el) {
        var nodeFill = el.rendNodeFill;
        
        if (el.visProp.gradient === 'linear') {
            this._setAttr(nodeFill, 'type', 'gradient');
            this._setAttr(nodeFill, 'color2', el.visProp.gradientsecondcolor);
            this._setAttr(nodeFill, 'opacity2', el.visProp.gradientsecondopacity);
            this._setAttr(nodeFill, 'angle', el.visProp.gradientangle);
        } else if (el.visProp.gradient === 'radial') {
            this._setAttr(nodeFill, 'type', 'gradientradial');
            this._setAttr(nodeFill, 'color2', el.visProp.gradientsecondcolor);
            this._setAttr(nodeFill, 'opacity2', el.visProp.gradientsecondopacity);
            this._setAttr(nodeFill, 'focusposition', el.visProp.gradientpositionx * 100 + '%,' + el.visProp.gradientpositiony * 100 + '%');
            this._setAttr(nodeFill, 'focussize', '0,0');
        } else {
            this._setAttr(nodeFill, 'type', 'solid');
        }
    },

    // already documented in JXG.AbstractRenderer
    setObjectFillColor: function (el, color, opacity) {
        var rgba = JXG.evaluate(color), c, rgbo,
            o = JXG.evaluate(opacity), oo,
            node = el.rendNode, 
            t;

        o = (o > 0) ? o : 0;

        if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o) {
            return;
        }

        if (JXG.exists(rgba) && rgba !== false) {
            if (rgba.length!=9) {          // RGB, not RGBA
                c = rgba;
                oo = o;
            } else {                       // True RGBA, not RGB
                rgbo = JXG.rgba2rgbo(rgba);
                c = rgbo[0];
                oo = o*rgbo[1];
            }
            if (c === 'none' || c === false) {
                this._setAttr(el.rendNode, 'filled', 'false');
            } else {
                this._setAttr(el.rendNode, 'filled', 'true');
                this._setAttr(el.rendNode, 'fillcolor', c);

                if (JXG.exists(oo) && el.rendNodeFill) {
                    this._setAttr(el.rendNodeFill, 'opacity', (oo * 100) + '%');
                }
            }
            if (el.type === JXG.OBJECT_TYPE_IMAGE) {
                t = el.rendNode.style.filter.toString();
                if (t.match(/alpha/)) {
                    el.rendNode.style.filter = t.replace(/alpha\(opacity *= *[0-9\.]+\)/, 'alpha(opacity = ' + (oo * 100) + ')');
                } else {
                    el.rendNode.style.filter += ' alpha(opacity = ' + (oo * 100) +')';
                }
            }
        }
        el.visPropOld.fillcolor = rgba;
        el.visPropOld.fillopacity = o;
    },

    // already documented in JXG.AbstractRenderer
    setObjectStrokeColor: function (el, color, opacity) {
        var rgba = JXG.evaluate(color), c, rgbo,
            o = JXG.evaluate(opacity), oo,
            node = el.rendNode, nodeStroke;

        o = (o > 0) ? o : 0;

        if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) {
            return;
        }

        if (JXG.exists(rgba) && rgba !== false) {
            if (rgba.length!=9) {          // RGB, not RGBA
                c = rgba;
                oo = o;
            } else {                       // True RGBA, not RGB
                rgbo = JXG.rgba2rgbo(rgba);
                c = rgbo[0];
                oo = o*rgbo[1];
            }
            if (el.type === JXG.OBJECT_TYPE_TEXT) {
                oo = Math.round(oo*100);
                node.style.filter = ' alpha(opacity = ' + oo +')';
                //node.style.filter = node.style['-ms-filter'] = "progid:DXImageTransform.Microsoft.Alpha(Opacity="+oo+")";
                node.style.color = c;
            } else {
                if (c !== false) {
                    this._setAttr(node, 'stroked', 'true');
                    this._setAttr(node, 'strokecolor', c);
                }

                nodeStroke = el.rendNodeStroke;
                if (JXG.exists(oo) && el.type !== JXG.OBJECT_TYPE_IMAGE) {
                    this._setAttr(nodeStroke, 'opacity', (oo * 100) + '%');
                }
            }
        }
        el.visPropOld.strokecolor = rgba;
        el.visPropOld.strokeopacity = o;
    },

    // already documented in JXG.AbstractRenderer
    setObjectStrokeWidth: function (el, width) {
        var w = JXG.evaluate(width),
            node;

        if (el.visPropOld.strokewidth === w) {
            return;
        }

        node = el.rendNode;
        this.setPropertyPrim(node, 'stroked', 'true');
        if (JXG.exists(w)) {
            this.setPropertyPrim(node, 'stroke-width', w);
        }
        el.visPropOld.strokewidth = w;
    },

    // already documented in JXG.AbstractRenderer
    setShadow: function (el) {
        var nodeShadow = el.rendNodeShadow;

        if (!nodeShadow || el.visPropOld.shadow === el.visProp.shadow) {
            return;
        }

        if (el.visProp.shadow) {
            this._setAttr(nodeShadow, 'On', 'True');
            this._setAttr(nodeShadow, 'Offset', '3pt,3pt');
            this._setAttr(nodeShadow, 'Opacity', '60%');
            this._setAttr(nodeShadow, 'Color', '#aaaaaa');
        } else {
            this._setAttr(nodeShadow, 'On', 'False');
        }

        el.visPropOld.shadow = el.visProp.shadow;
    },

    /* **************************
     * renderer control
     * **************************/

    // already documented in JXG.AbstractRenderer
    suspendRedraw: function () {
        this.container.style.display = 'none';
    },

    // already documented in JXG.AbstractRenderer
    unsuspendRedraw: function () {
        this.container.style.display = '';
    }

});

/*
    Copyright 2010-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Bianca Valentin,
        Alfred Wassermann,
        Peter Wilfahrt

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

/*jshint bitwise: false, curly: true, debug: false, eqeqeq: true, devel: false, evil: false,
  forin: false, immed: true, laxbreak: false, newcap: false, noarg: true, nonew: true, onevar: true,
   undef: true, white: false, sub: false*/
/*global JXG: true, AMprocessNode: true, document: true, Image: true */

/**
 * Uses HTML Canvas to implement the rendering methods defined in {@link JXG.AbstractRenderer}.
 * @class JXG.AbstractRenderer
 * @augments JXG.AbstractRenderer
 * @param {Node} container Reference to a DOM node containing the board.
 * @see JXG.AbstractRenderer
 */
JXG.CanvasRenderer = function (container) {
    var i;

    this.type = 'canvas';

    this.canvasRoot = null;
    this.suspendHandle = null;
    this.canvasId = JXG.Util.genUUID();

    this.canvasNamespace = null;

    if (typeof document !== 'undefined') {
        this.container = container;
        this.container.style.MozUserSelect = 'none';

        this.container.style.overflow = 'hidden';
        if (this.container.style.position === '') {
            this.container.style.position = 'relative';
        }

        this.container.innerHTML = ['<canvas id="', this.canvasId, '" width="', JXG.getStyle(this.container, 'width'), '" height="', JXG.getStyle(this.container, 'height'), '"><', '/canvas>'].join('');
        this.canvasRoot = document.getElementById(this.canvasId);
        this.context =  this.canvasRoot.getContext('2d');
    } else if (JXG.isNode()) {
        this.canvasId = require('canvas');
        this.canvasRoot = new this.canvasId(500, 500);
        this.context = this.canvasRoot.getContext('2d');
    }

    this.dashArray = [[2, 2], [5, 5], [10, 10], [20, 20], [20, 10, 10, 10], [20, 5, 10, 5]];
};

JXG.CanvasRenderer.prototype = new JXG.AbstractRenderer();

JXG.extend(JXG.CanvasRenderer.prototype, /** @lends JXG.CanvasRenderer.prototype */ {

    /* **************************
     *   private methods only used
     *   in this renderer. Should
     *   not be called from outside.
     * **************************/

    /**
     * Draws a filled polygon.
     * @param {Array} shape A matrix presented by a two dimensional array of numbers.
     * @see JXG.AbstractRenderer#makeArrows
     * @private
     */
    _drawFilledPolygon: function (shape) {
        var i, len = shape.length,
            context = this.context;

        if (len > 0) {
            context.beginPath();
            context.moveTo(shape[0][0], shape[0][1]);
            for (i = 0; i < len; i++) {
                if (i > 0) {
                    context.lineTo(shape[i][0], shape[i][1]);
                }
            }
            context.lineTo(shape[0][0], shape[0][1]);
            context.fill();
        }
    },

    /**
     * Sets the fill color and fills an area.
     * @param {JXG.GeometryElement} element An arbitrary JSXGraph element, preferably one with an area.
     * @private
     */
    _fill: function (element) {
        var context = this.context;

        context.save();
        if (this._setColor(element, 'fill')) {
            context.fill();
        }
        context.restore();
    },

    /**
     * Rotates a point around <tt>(0, 0)</tt> by a given angle.
     * @param {Number} angle An angle, given in rad.
     * @param {Number} x X coordinate of the point.
     * @param {Number} y Y coordinate of the point.
     * @returns {Array} An array containing the x and y coordinate of the rotated point.
     * @private
     */
    _rotatePoint: function (angle, x, y) {
        return [
            (x * Math.cos(angle)) - (y * Math.sin(angle)),
            (x * Math.sin(angle)) + (y * Math.cos(angle))
        ];
    },

    /**
     * Rotates an array of points around <tt>(0, 0)</tt>.
     * @param {Array} shape An array of array of point coordinates.
     * @param {Number} angle The angle in rad the points are rotated by.
     * @returns {Array} Array of array of two dimensional point coordinates.
     * @private
     */
    _rotateShape: function (shape, angle) {
        var i, rv = [], len = shape.length;

        if (len <= 0) {
            return shape;
        }

        for (i = 0; i < len; i++) {
            rv.push(this._rotatePoint(angle, shape[i][0], shape[i][1]));
        }

        return rv;
    },

    /**
     * Sets color and opacity for filling and stroking.
     * type is the attribute from visProp and targetType the context[targetTypeStyle].
     * This is necessary, because the fill style of a text is set by the stroke attributes of the text element.
     * @param {JXG.GeometryElement} element Any JSXGraph element.
     * @param {String} [type='stroke'] Either <em>fill</em> or <em>stroke</em>.
     * @param {String} [targetType=type] (optional) Either <em>fill</em> or <em>stroke</em>.
     * @returns {Boolean} If the color could be set, <tt>true</tt> is returned.
     * @private
     */
    _setColor: function (element, type, targetType) {
        var hasColor = true, isTrace = false, 
            ev = element.visProp, hl,
            rgba, rgbo, c, o, oo;

        type = type || 'stroke';
        targetType = targetType || type;
        if (!JXG.exists(element.board) || !JXG.exists(element.board.highlightedObjects)) {
            // This case handles trace elements.
            // To make them work, we simply neglect highlighting.
            isTrace = true;
        }

        if (!isTrace && JXG.exists(element.board.highlightedObjects[element.id])) {
            hl = 'highlight';
        } else {
            hl = '';
        }

        // type is equal to 'fill' or 'stroke'
        rgba = JXG.evaluate(ev[hl+type+'color']);
        if (rgba !== 'none' && rgba !== false ) {
            o = JXG.evaluate(ev[hl+type+'opacity']);
            o = (o > 0) ? o : 0;
            if (rgba.length!=9) {          // RGB, not RGBA
                c = rgba;
                oo = o;
            } else {                       // True RGBA, not RGB
                rgbo = JXG.rgba2rgbo(rgba);
                c = rgbo[0];
                oo = o*rgbo[1];
            }
            this.context.globalAlpha = oo;


            this.context[targetType+'Style'] = c;

        } else {
            hasColor = false;
        }
        if (type === 'stroke') {
            this.context.lineWidth = parseFloat(ev.strokewidth);
        }
        return hasColor;
    },


    /**
     * Sets color and opacity for drawing paths and lines and draws the paths and lines.
     * @param {JXG.GeometryElement} element An JSXGraph element with a stroke.
     * @private
     */
    _stroke: function (element) {
        var context = this.context;

        context.save();

        if (element.visProp.dash > 0) {
            if (context.setLineDash) {
                context.setLineDash(this.dashArray[element.visProp.dash]);
            }
        } else {
            this.context.lineDashArray = [];
        }

        if (this._setColor(element, 'stroke')) {
            context.stroke();
        }

        context.restore();
    },

    /**
     * Translates a set of points.
     * @param {Array} shape An array of point coordinates.
     * @param {Number} x Translation in X direction.
     * @param {Number} y Translation in Y direction.
     * @returns {Array} An array of translated point coordinates.
     * @private
     */
    _translateShape: function (shape, x, y) {
        var i, rv = [], len = shape.length;

        if (len <= 0) {
            return shape;
        }

        for (i = 0; i < len; i++) {
            rv.push([ shape[i][0] + x, shape[i][1] + y ]);
        }

        return rv;
    },

    /* ******************************** *
     *    Point drawing and updating    *
     * ******************************** */

    // documented in AbstractRenderer
    drawPoint: function (el) {
        var f = el.visProp.face,
            size = el.visProp.size,
            scr = el.coords.scrCoords,
            sqrt32 = size * Math.sqrt(3) * 0.5,
            s05 = size * 0.5,
            stroke05 = parseFloat(el.visProp.strokewidth) / 2.0,
            context = this.context;

        switch (f) {
            case 'cross':  // x
            case 'x':
                context.beginPath();
                context.moveTo(scr[1] - size, scr[2] - size);
                context.lineTo(scr[1] + size, scr[2] + size);
                context.moveTo(scr[1] + size, scr[2] - size);
                context.lineTo(scr[1] - size, scr[2] + size);
                context.closePath();
                this._stroke(el);
                break;
            case 'circle': // dot
            case 'o':
                context.beginPath();
                context.arc(scr[1], scr[2], size + 1 + stroke05, 0, 2 * Math.PI, false);
                context.closePath();
                this._fill(el);
                this._stroke(el);
                break;
            case 'square':  // rectangle
            case '[]':
                if (size <= 0) {
                    break;
                }

                context.save();
                if (this._setColor(el, 'stroke', 'fill')) {
                    context.fillRect(scr[1] - size - stroke05, scr[2] - size - stroke05, size * 2 + 3 * stroke05, size * 2 + 3 * stroke05);
                }
                context.restore();
                context.save();
                this._setColor(el, 'fill');
                context.fillRect(scr[1] - size + stroke05, scr[2] - size + stroke05, size * 2 - stroke05, size * 2 - stroke05);
                context.restore();
                break;
            case 'plus':  // +
            case '+':
                context.beginPath();
                context.moveTo(scr[1] - size, scr[2]);
                context.lineTo(scr[1] + size, scr[2]);
                context.moveTo(scr[1], scr[2] - size);
                context.lineTo(scr[1], scr[2] + size);
                context.closePath();
                this._stroke(el);
                break;
            case 'diamond':   // <>
            case '<>':
                context.beginPath();
                context.moveTo(scr[1] - size, scr[2]);
                context.lineTo(scr[1], scr[2] + size);
                context.lineTo(scr[1] + size, scr[2]);
                context.lineTo(scr[1], scr[2] - size);
                context.closePath();
                this._fill(el);
                this._stroke(el);
                break;
            case 'triangleup':
            case 'a':
            case '^':
                context.beginPath();
                context.moveTo(scr[1], scr[2] - size);
                context.lineTo(scr[1] - sqrt32, scr[2] + s05);
                context.lineTo(scr[1] + sqrt32, scr[2] + s05);
                context.closePath();
                this._fill(el);
                this._stroke(el);
                break;
            case 'triangledown':
            case 'v':
                context.beginPath();
                context.moveTo(scr[1], scr[2] + size);
                context.lineTo(scr[1] - sqrt32, scr[2] - s05);
                context.lineTo(scr[1] + sqrt32, scr[2] - s05);
                context.closePath();
                this._fill(el);
                this._stroke(el);
                break;
            case 'triangleleft':
            case '<':
                context.beginPath();
                context.moveTo(scr[1] - size, scr[2]);
                context.lineTo(scr[1] + s05, scr[2] - sqrt32);
                context.lineTo(scr[1] + s05, scr[2] + sqrt32);
                context.closePath();
                this.fill(el);
                this._stroke(el);
                break;
            case 'triangleright':
            case '>':
                context.beginPath();
                context.moveTo(scr[1] + size, scr[2]);
                context.lineTo(scr[1] - s05, scr[2] - sqrt32);
                context.lineTo(scr[1] - s05, scr[2] + sqrt32);
                context.closePath();
                this._fill(el);
                this._stroke(el);
                break;
        }
    },

    // documented in AbstractRenderer
    updatePoint: function (el) {
        this.drawPoint(el);
    },

    /* ******************************** *
     *           Lines                  *
     * ******************************** */

    // documented in AbstractRenderer
    drawLine: function (el) {
        var scr1 = new JXG.Coords(JXG.COORDS_BY_USER, el.point1.coords.usrCoords, el.board),
            scr2 = new JXG.Coords(JXG.COORDS_BY_USER, el.point2.coords.usrCoords, el.board);

        JXG.Math.Geometry.calcStraight(el, scr1, scr2);

        this.context.beginPath();
        this.context.moveTo(scr1.scrCoords[1], scr1.scrCoords[2]);
        this.context.lineTo(scr2.scrCoords[1], scr2.scrCoords[2]);
        this._stroke(el);

        this.makeArrows(el, scr1, scr2);
    },

    // documented in AbstractRenderer
    updateLine: function (el) {
        this.drawLine(el);
    },

    // documented in AbstractRenderer
    drawTicks: function () {
        // this function is supposed to initialize the svg/vml nodes in the SVG/VMLRenderer.
        // but in canvas there are no such nodes, hence we just do nothing and wait until
        // updateTicks is called.
    },

    // documented in AbstractRenderer
    updateTicks: function (axis, dxMaj, dyMaj, dxMin, dyMin) {
        var i, c,
            len = axis.ticks.length,
            context = this.context;

        context.beginPath();
        for (i = 0; i < len; i++) {
            c = axis.ticks[i];
            x = c[0];
            y = c[1];
            context.moveTo(x[0], y[0]);
            context.lineTo(x[1], y[1]);
        }
        // Labels
        for (i = 0; i < len; i++) {
            c = axis.ticks[i].scrCoords;
            if (axis.ticks[i].major 
                && (axis.board.needsFullUpdate || axis.needsRegularUpdate) 
                && axis.labels[i] 
                && axis.labels[i].visProp.visible) {
                    this.updateText(axis.labels[i]);
            } 
        }
        this._stroke(axis);
    },

    /* **************************
     *    Curves
     * **************************/

    // documented in AbstractRenderer
    drawCurve: function (el) {
        if (el.visProp.handdrawing) {
            this.updatePathStringBezierPrim(el);
        } else {		
            this.updatePathStringPrim(el);
        }
    },

    // documented in AbstractRenderer
    updateCurve: function (el) {
        this.drawCurve(el);
    },

    /* **************************
     *    Circle related stuff
     * **************************/

    // documented in AbstractRenderer
    drawEllipse: function (el) {
        var m1 = el.center.coords.scrCoords[1],
            m2 = el.center.coords.scrCoords[2],
            sX = el.board.unitX,
            sY = el.board.unitY,
            rX = 2 * el.Radius(),
            rY = 2 * el.Radius(),
            aWidth = rX * sX,
            aHeight = rY * sY,
            aX = m1 - aWidth / 2,
            aY = m2 - aHeight / 2,
            hB = (aWidth / 2) * 0.5522848,
            vB = (aHeight / 2) * 0.5522848,
            eX = aX + aWidth,
            eY = aY + aHeight,
            mX = aX + aWidth / 2,
            mY = aY + aHeight / 2,
            context = this.context;

        if (rX > 0.0 && rY > 0.0 && !isNaN(m1 + m2)) {
            context.beginPath();
            context.moveTo(aX, mY);
            context.bezierCurveTo(aX, mY - vB, mX - hB, aY, mX, aY);
            context.bezierCurveTo(mX + hB, aY, eX, mY - vB, eX, mY);
            context.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY);
            context.bezierCurveTo(mX - hB, eY, aX, mY + vB, aX, mY);
            context.closePath();
            this._fill(el);
            this._stroke(el);
        }
    },

    // documented in AbstractRenderer
    updateEllipse: function (el) {
        return this.drawEllipse(el);
    },

    /* **************************
     *    Polygon
     * **************************/

    // nothing here, using AbstractRenderer implementations

    /* **************************
     *    Text related stuff
     * **************************/

    // already documented in JXG.AbstractRenderer
    displayCopyright: function (str, fontSize) {
        var context = this.context;

        // this should be called on EVERY update, otherwise it won't be shown after the first update
        context.save();
        context.font = fontSize + 'px Arial';
        context.fillStyle = '#aaa';
        context.lineWidth = 0.5;
        context.fillText(str, 10, 2 + fontSize);
        context.restore();
    },

    // already documented in JXG.AbstractRenderer
    drawInternalText: function (el) {
        var fs, context = this.context;

        context.save();
        // el.rendNode.setAttributeNS(null, "class", el.visProp.cssclass);
        if (this._setColor(el, 'stroke', 'fill') && !isNaN(el.coords.scrCoords[1]+el.coords.scrCoords[2]) ) {
            if (el.visProp.fontsize) {
                if (typeof el.visProp.fontsize === 'function') {
                    fs = el.visProp.fontsize();
                    context.font = (fs > 0 ? fs : 0) + 'px Arial';
                } else {
                    context.font = (el.visProp.fontsize) + 'px Arial';
                }
            }

            this.transformImage(el, el.transformations);
            if (el.visProp.anchorx === 'right') {
                context.textAlign = 'right';
            } else if (el.visProp.anchorx === 'middle') {
                context.textAlign = 'center';
            }
            if (el.visProp.anchory === 'top') {
                context.textBaseline = 'top';
            } else if (el.visProp.anchory === 'middle') {
                context.textBaseline = 'middle';
            }
            context.fillText(el.plaintext, el.coords.scrCoords[1], el.coords.scrCoords[2]);
        }
        context.restore();

        return null;
    },

    // already documented in JXG.AbstractRenderer
    updateInternalText: function (element) {
        this.drawInternalText(element);
    },

    // documented in JXG.AbstractRenderer
    // Only necessary for texts
    setObjectStrokeColor: function (el, color, opacity) {
        var rgba = JXG.evaluate(color), c, rgbo,
            o = JXG.evaluate(opacity), oo,
            node;

        o = (o > 0) ? o : 0;

        if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) {
            return;
        }

        if (JXG.exists(rgba) && rgba !== false) {
            if (rgba.length!=9) {          // RGB, not RGBA
                c = rgba;
                oo = o;
            } else {                       // True RGBA, not RGB
                rgbo = JXG.rgba2rgbo(rgba);
                c = rgbo[0];
                oo = o*rgbo[1];
            }
            node = el.rendNode;
            if (el.type === JXG.OBJECT_TYPE_TEXT && el.visProp.display === 'html') {
                node.style.color = c;     
                node.style.opacity = oo;
            }
        }

        el.visPropOld.strokecolor = rgba;
        el.visPropOld.strokeopacity = o;
    },

    // already documented in JXG.AbstractRenderer
/*    
    updateTextStyle: function (element) { 
        var fs = JXG.evaluate(element.visProp.fontsize);

        if (element.visProp.display === 'html') {
            element.rendNode.style.fontSize = fs + 'px';
        }
    },
*/
    /* **************************
     *    Image related stuff
     * **************************/

    // already documented in JXG.AbstractRenderer
    drawImage: function (el) {
        el.rendNode = new Image();
        // Store the file name of the image.
        // Before, this was done in el.rendNode.src
        // But there, the file name is expanded to
        // the full url. This may be different from
        // the url computed in updateImageURL().
        el._src = '';
        this.updateImage(el);
    },

    // already documented in JXG.AbstractRenderer
    updateImage: function (el) {
        var context = this.context,
            o = JXG.evaluate(el.visProp.fillopacity),
            paintImg = JXG.bind(function () {
                el.imgIsLoaded = true;
                if (el.size[0] <= 0 || el.size[1] <= 0) {
                    return;
                }
                context.save();
                context.globalAlpha = o;
                // If det(el.transformations)=0, FireFox 3.6. breaks down.
                // This is tested in transformImage
                this.transformImage(el, el.transformations);
                context.drawImage(el.rendNode,
                    el.coords.scrCoords[1],
                    el.coords.scrCoords[2] - el.size[1],
                    el.size[0],
                    el.size[1]);
                context.restore();
            }, this);

        if (this.updateImageURL(el)) {
            el.rendNode.onload = paintImg;
        } else {
            if (el.imgIsLoaded) {
                paintImg();
            }
        }
    },

    // already documented in JXG.AbstractRenderer
    transformImage: function (el, t) {
        var m, len = t.length,
            ctx = this.context;

        if (len > 0) {
            m = this.joinTransforms(el, t);
            if (Math.abs(JXG.Math.Numerics.det(m)) >= JXG.Math.eps) {
                ctx.transform(m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]);
            }
        }
    },

    // already documented in JXG.AbstractRenderer
    updateImageURL: function (el) {
        var url;

        url = JXG.evaluate(el.url);
        if (el._src !== url) {
            el.imgIsLoaded = false;
            el.rendNode.src = url;
            el._src = url;
            return true;
        }

        return false;
    },

    /* **************************
     * Render primitive objects
     * **************************/

    // documented in AbstractRenderer
    remove: function (shape) {
        // sounds odd for a pixel based renderer but we need this for html texts
        if (JXG.exists(shape) && JXG.exists(shape.parentNode)) {
            shape.parentNode.removeChild(shape);
        }
    },

    // documented in AbstractRenderer
    makeArrows: function (el, scr1, scr2) {
        // not done yet for curves and arcs.
        var w = Math.min(el.visProp.strokewidth/2, 3),
            arrowHead = [
            [ 2, 0 ],
            [ -10, -4*w ],
            [ -10, 4*w],
            [ 2, 0 ]
        ],
            arrowTail = [
                [ -2, 0 ],
                [ 10, -4*w ],
                [ 10, 4*w]
            ],
            x1, y1, x2, y2, ang,
            context = this.context;

        if (el.visProp.strokecolor !== 'none' && (el.visProp.lastarrow || el.visProp.firstarrow)) {
            if (el.elementClass === JXG.OBJECT_CLASS_LINE) {
                x1 = scr1.scrCoords[1];
                y1 = scr1.scrCoords[2];
                x2 = scr2.scrCoords[1];
                y2 = scr2.scrCoords[2];
            } else {
                return;
            }

            context.save();
            if (this._setColor(el, 'stroke', 'fill')) {
                ang = Math.atan2(y2 - y1, x2 - x1);
                if (el.visProp.lastarrow) {
                    this._drawFilledPolygon(this._translateShape(this._rotateShape(arrowHead, ang), x2, y2));
                }

                if (el.visProp.firstarrow) {
                    this._drawFilledPolygon(this._translateShape(this._rotateShape(arrowTail, ang), x1, y1));
                }
            }
            context.restore();
        }
    },

    // documented in AbstractRenderer
    updatePathStringPrim: function (el) {
        var symbm = 'M',
            symbl = 'L',
            symbc = 'C',
            nextSymb = symbm,
            maxSize = 5000.0,
            i, scr, scr1, scr2,
            isNotPlot = (el.visProp.curvetype !== 'plot'),
            len,
            context = this.context;

        if (el.numberPoints <= 0) {
            return;
        }
        len = Math.min(el.points.length, el.numberPoints);
        context.beginPath();
        
        if (el.bezierDegree == 1) {
            if (isNotPlot && el.board.options.curve.RDPsmoothing) {
                el.points = JXG.Math.Numerics.RamerDouglasPeuker(el.points, 0.5);
            }

            for (i = 0; i < len; i++) {
                scr = el.points[i].scrCoords;

                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    // Chrome has problems with values  being too far away.
                    if (scr[1] > maxSize) {
                        scr[1] = maxSize;
                    } else if (scr[1] < -maxSize) {
                        scr[1] = -maxSize;
                    }

                    if (scr[2] > maxSize) {
                        scr[2] = maxSize;
                    } else if (scr[2] < -maxSize) {
                        scr[2] = -maxSize;
                    }

                    if (nextSymb === symbm) {
                        context.moveTo(scr[1], scr[2]);
                    } else {
                        context.lineTo(scr[1], scr[2]);
                    }
                    nextSymb = symbl;
                }
            }
        } else if (el.bezierDegree==3) {
            i = 0;
            while (i < len) {
                scr = el.points[i].scrCoords;
                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    if (nextSymb === symbm) {
                        context.moveTo(scr[1], scr[2]);
                    } else {
                        i++; scr1 = el.points[i].scrCoords;
                        i++; scr2 = el.points[i].scrCoords;
                        context.bezierCurveTo(scr[1], scr[2], scr1[1], scr1[2], scr2[1], scr2[2]);
                                              
//console.log(scr[1], scr[2], scr1[1], scr1[2], scr2[1], scr2[2]);                        
                    }
                    nextSymb = symbc;
                }
                i++;
            }
        }
        this._fill(el);
        this._stroke(el);
    },

    // already documented in JXG.AbstractRenderer
    updatePathStringBezierPrim: function (el) {
        var symbm = 'M',
            symbl = 'C',
            nextSymb = symbm,
            maxSize = 5000.0,
            i, j, scr,
            lx, ly, f = el.visProp.strokewidth, 
            isNoPlot = (el.visProp.curvetype !== 'plot'),
            len,
            context = this.context;

        if (el.numberPoints <= 0) {
            return;
        }

        if (isNoPlot && el.board.options.curve.RDPsmoothing) {
            el.points = JXG.Math.Numerics.RamerDouglasPeuker(el.points, 0.5);
        }
        len = Math.min(el.points.length, el.numberPoints);

        context.beginPath();
        for (j=1; j<3; j++) {
            nextSymb = symbm;
            for (i = 0; i < len; i++) {
                scr = el.points[i].scrCoords;

                if (isNaN(scr[1]) || isNaN(scr[2])) {  // PenUp
                    nextSymb = symbm;
                } else {
                    // Chrome has problems with values  being too far away.
                    if (scr[1] > maxSize) {
                        scr[1] = maxSize;
                    } else if (scr[1] < -maxSize) {
                        scr[1] = -maxSize;
                    }

                    if (scr[2] > maxSize) {
                        scr[2] = maxSize;
                    } else if (scr[2] < -maxSize) {
                        scr[2] = -maxSize;
                    }

                    if (nextSymb == symbm) {
                        context.moveTo(scr[1]+0*f*(2*j*Math.random()-j), 
                                       scr[2]+0*f*(2*j*Math.random()-j));
                    } else {
                        context.bezierCurveTo(
                            (lx + (scr[1]-lx)*0.333 + f*(2*j*Math.random()-j)),
                            (ly + (scr[2]-ly)*0.333 + f*(2*j*Math.random()-j)),
                            (lx + 2*(scr[1]-lx)*0.333 + f*(2*j*Math.random()-j)),
                            (ly + 2*(scr[2]-ly)*0.333 + f*(2*j*Math.random()-j)),
                            scr[1], scr[2]);
                    }
                    nextSymb = symbl;
                    lx = scr[1];
                    ly = scr[2];
                }
            }
        }
        this._fill(el);
        this._stroke(el);
    },

    // documented in AbstractRenderer
    updatePolygonPrim: function (node, el) {
        var scrCoords, i,
            len = el.vertices.length,
            context = this.context, isReal=true;

        if (len <= 0) {
            return;
        }

        context.beginPath();
        i = 0;
        while (!el.vertices[i].isReal && i<len-1) { 
            i++; 
            isReal = false;
        }
        scrCoords = el.vertices[i].coords.scrCoords;
        context.moveTo(scrCoords[1], scrCoords[2]);
        for (i = i; i < len-1; i++) {
            if (!el.vertices[i].isReal) { 
                isReal = false; 
            }
            scrCoords = el.vertices[i].coords.scrCoords;
            context.lineTo(scrCoords[1], scrCoords[2]);
        }
        context.closePath();

        if (isReal) {
            this._fill(el);    // The edges of a polygon are displayed separately (as segments).
        }
    },

    /* **************************
     *  Set Attributes
     * **************************/

    // documented in AbstractRenderer
    show: function (el) {
        // sounds odd for a pixel based renderer but we need this for html texts
        if (JXG.exists(el.rendNode)) {
            el.rendNode.style.visibility = "inherit";
        }
    },

    // documented in AbstractRenderer
    hide: function (el) {
        // sounds odd for a pixel based renderer but we need this for html texts
        if (JXG.exists(el.rendNode)) {
            el.rendNode.style.visibility = "hidden";
        }
    },

    // documented in AbstractRenderer
    setGradient: function (el) {
        var col, op;

        op = JXG.evaluate(el.visProp.fillopacity);
        op = (op > 0) ? op : 0;

        col = JXG.evaluate(el.visProp.fillcolor);
    },

    // documented in AbstractRenderer
    setShadow: function (el) {
        if (el.visPropOld.shadow === el.visProp.shadow) {
            return;
        }

        // not implemented yet
        // we simply have to redraw the element
        // probably the best way to do so would be to call el.updateRenderer(), i think.

        el.visPropOld.shadow = el.visProp.shadow;
    },

    // documented in AbstractRenderer
    highlight: function (obj) {
        if (obj.type === JXG.OBJECT_TYPE_TEXT && obj.visProp.display === 'html') {
            this.updateTextStyle(obj, true);
        } else {
            obj.board.prepareUpdate();
            obj.board.renderer.suspendRedraw(obj.board);
            obj.board.updateRenderer();
            obj.board.renderer.unsuspendRedraw();
        }
        return this;
    },

    // documented in AbstractRenderer
    noHighlight: function (obj) {
        if (obj.type === JXG.OBJECT_TYPE_TEXT && obj.visProp.display === 'html') {
            this.updateTextStyle(obj, false);
        } else {
            obj.board.prepareUpdate();
            obj.board.renderer.suspendRedraw(obj.board);
            obj.board.updateRenderer();
            obj.board.renderer.unsuspendRedraw();
        }
        return this;
    },

    /* **************************
     * renderer control
     * **************************/

    // documented in AbstractRenderer
    suspendRedraw: function (board) {
        this.context.save();

        this.context.clearRect(0, 0, this.canvasRoot.width, this.canvasRoot.height);

        if (board && board.showCopyright) {
            this.displayCopyright(JXG.JSXGraph.licenseText, 12);
        }
    },

    // documented in AbstractRenderer
    unsuspendRedraw: function () {
        this.context.restore();
    },

    // document in AbstractRenderer
    resize: function (w, h) {
        if (this.container) {
            this.canvasRoot.style.width = parseFloat(w) + 'px';
            this.canvasRoot.style.height = parseFloat(h) + 'px';

            this.canvasRoot.setAttribute('width', parseFloat(w) + 'px');
            this.canvasRoot.setAttribute('height', parseFloat(h) + 'px');
        } else {
            this.canvasRoot.width = parseFloat(w);
            this.canvasRoot.height = parseFloat(h);
        }
    }

});

/*
    Copyright 2008-2011
        Matthias Ehmann,
        Michael Gerhaeuser,
        Carsten Miller,
        Heiko Vogel
        Alfred Wassermann,

    This file is part of JSXGraph.

    JSXGraph is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JSXGraph is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
*/

JXG.extend(JXG, {

    GENTYPE_ABC: 1, // unused
    GENTYPE_AXIS: 2,
    GENTYPE_MID: 3,
    GENTYPE_REFLECTION: 4,
    GENTYPE_MIRRORPOINT: 5,
    GENTYPE_TANGENT: 6,
    GENTYPE_PARALLEL: 7,
    GENTYPE_BISECTORLINES: 8,
    GENTYPE_PERPENDICULAR_BISECTOR: 9,
    GENTYPE_BISECTOR: 10,
    GENTYPE_NORMAL: 11,
    GENTYPE_POINT: 12,
    GENTYPE_GLIDER: 13,
    GENTYPE_INTERSECTION: 14,
    GENTYPE_CIRCLE: 15,
    GENTYPE_CIRCLE2POINTS: 16,
    GENTYPE_LINE: 17,
    GENTYPE_TRIANGLE: 18,
    GENTYPE_QUADRILATERAL: 19,
    GENTYPE_TEXT: 20,
    GENTYPE_POLYGON: 21,
    GENTYPE_REGULARPOLYGON: 22,
    GENTYPE_SECTOR: 23,
    GENTYPE_ANGLE: 24,
    GENTYPE_PLOT: 25,
    GENTYPE_SLIDER: 26,
    GENTYPE_XYZ: 27, // unused ...
    GENTYPE_JCODE: 28,
    GENTYPE_MOVEMENT: 29,

    // 30 ... 32 // unused ...

    GENTYPE_GRID: 33, // obsolete

    // 34 ... 39 // unused ...

    GENTYPE_DELETE: 41,
    GENTYPE_COPY: 42,
    GENTYPE_MIRROR: 43,
    GENTYPE_ROTATE: 44,
    GENTYPE_ABLATION: 45,
    GENTYPE_MIGRATE: 46,
    GENTYPE_TRANSFORM: 47,

    // 48 ... 50 // unused ...

    /*
     Important:
     ==========

     For being able to differentiate between the (GUI-specific) CTX and
     (CORE-specific) non-CTX steps, the non-CTX steps must not be changed
     to values > 50 !!!
     */

    GENTYPE_CTX_TYPE_G: 51,
    GENTYPE_CTX_TYPE_P: 52,
    GENTYPE_CTX_TRACE: 53,
    GENTYPE_CTX_VISIBILITY: 54,
    GENTYPE_CTX_CCVISIBILITY: 55,
    GENTYPE_CTX_MPVISIBILITY: 56,
    GENTYPE_CTX_WITHLABEL: 57,
    GENTYPE_CTX_SETLABEL: 58,
    GENTYPE_CTX_SETFIXED: 59,
    GENTYPE_CTX_STROKEWIDTH: 60,
    GENTYPE_CTX_LABELSIZE: 61,
    GENTYPE_CTX_SIZE: 62,
    GENTYPE_CTX_FACE: 63,
    GENTYPE_CTX_STRAIGHT: 64,
    GENTYPE_CTX_ARROW: 65,
    GENTYPE_CTX_COLOR: 66,
    GENTYPE_CTX_RADIUS: 67,
    GENTYPE_CTX_COORDS: 68,
    GENTYPE_CTX_TEXT: 69,
    GENTYPE_CTX_ANGLERADIUS: 70,
    GENTYPE_CTX_DOTVISIBILITY: 71,
    GENTYPE_CTX_FILLOPACITY: 72,

    SketchReader: {

        generator: {
            toFixed: 0,
            freeLine: false,
            useGlider: false,
            useSymbols: false
        },
        // configure the generator below

        generateJCodeMeta: function () {},

        id: function () {
            return JXG.Util.genUUID();
        },

        generateJCode: function (step, board, step_log) {

            // step has to be an objectliteral of the form: { type, args, src_ids, dest_sub_ids, dest_id }

            var options, assign, attrid, obj, type;

            var i, j, k, sub_id, str, str1, str2, objects, pid1, pid2, pid3, xstart, ystart, el, bo, arr,
                xy, sxy, sxyc, step2, copy_log = [];

            var set_str = '', reset_str = '', ctx_set_str = '', ctx_reset_str = '';

            options = JXG.SketchReader.generator;

            objects = board.objects;

            // print number -- helper to prepare numbers
            // for printing, e.g. trim them with toFixed()

            var pn = function (v) {
                if (options.toFixed > 0)
                    v = v.toFixed(options.toFixed);
                return v;
            };

            var getObject = function (v) {
                var o;

                if (options.useSymbols) {
                    if (board.jc.sstack[0][v]) {
                        o = board.jc.sstack[0][v];
                    } else {
                        o = objects[v];
                    }
                } else {
                    o = objects[v];
                }

                return o;
            };

            /* SKETCHBIN begin */

            assign = '';
            attrid = 'id: \'' + step.dest_id + '\', ';

            if (JXG.exists(board) && options.useSymbols && step.type !== JXG.GENTYPE_ABLATION) {
                attrid = '';
                assign = step.dest_id + ' = ';

                for (i = 0; i < step.src_ids.length; i++) {
                    str = board.jc.findSymbol(getObject(step.src_ids[i]), 0); // Das Board wird hier immer benötigt!!!

                    if (str.length > 0) {
                        step.src_ids[i] = str[0];
                    }
                }
            }

            /* SKETCHBIN end */

            if (step.type > 50)
                return JXG.SketchReader.generateJCodeMeta(step, board);

            switch (step.type) {

                case JXG.GENTYPE_JCODE:
                    set_str = step.args.code;
                    break;

                case JXG.GENTYPE_AXIS:
                    set_str = step.args.name[0] + ' = point(' + pn(step.args.coords[0].usrCoords[1]) + ', ';
                    set_str += pn(step.args.coords[0].usrCoords[2]) + ') <<id: \'' + step.dest_sub_ids[0] + '\', name: \'';
                    set_str += step.args.name[0] + '\', fixed: true, priv: true, visible: false>>; ' + step.args.name[1];
                    set_str += ' = point(' + pn(step.args.coords[1].usrCoords[1]) + ', ';
                    set_str += pn(step.args.coords[1].usrCoords[2]) + ') <<id: \'' + step.dest_sub_ids[1] + '\', name: \'';
                    set_str += step.args.name[1] + '\', fixed: true, priv: true, visible: false>>; ' + step.args.name[2];
                    set_str += ' = point(' + pn(step.args.coords[2].usrCoords[1]) + ', ';
                    set_str += pn(step.args.coords[2].usrCoords[2]) + ') <<id: \'' + step.dest_sub_ids[2] + '\', name: \'';
                    set_str += step.args.name[2] + '\', fixed: true, priv: true, visible: false>>; ';

                    set_str += step.args.name[3] + ' = axis(' + step.args.name[0] + ', ' + step.args.name[1] + ') ';
                    set_str += '<<id: \'' + step.dest_sub_ids[3] + '\', name: \'' + step.args.name[3] + '\', ticks: ';
                    set_str += '<<minorHeight:0, majorHeight:10, ticksDistance: ' + JXG.Options.axisScaleX;
                    set_str += ', drawLabels: true, drawZero: true>>>>; ';
                    set_str += step.args.name[4] + ' = axis(' + step.args.name[0] + ', ' + step.args.name[2] + ') ';
                    set_str += '<<id: \'' + step.dest_sub_ids[4] + '\', name: \'' + step.args.name[4] + '\', ticks: ';
                    set_str += '<<minorHeight:0, majorHeight:10, ticksDistance: ' + JXG.Options.axisScaleY;
                    set_str += ', drawLabels: true, drawZero: true>>>>; ';

                    set_str += step.dest_sub_ids[3] + '.visible = false; ';
                    set_str += step.dest_sub_ids[4] + '.visible = false; ';

                    set_str += 'delete jxgBoard1_infobox; ';

                    reset_str = 'delete ' + step.dest_sub_ids[4] + '; delete ' + step.dest_sub_ids[3];
                    reset_str += '; delete ' + step.dest_sub_ids[2] + '; ';
                    reset_str += 'delete ' + step.dest_sub_ids[1] + '; delete ' + step.dest_sub_ids[0] + '; ';

                    break;

                case JXG.GENTYPE_MID:
                    set_str = assign + 'midpoint(' + step.src_ids[0] + ', ' + step.src_ids[1] + ') <<' + attrid;
                    set_str += 'fillColor: \'' + step.args.fillColor + '\'>>; ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_REFLECTION:
                    set_str = assign + 'reflection(' + step.src_ids[0] + ', ' + step.src_ids[1] + ') <<' + attrid;
                    set_str += 'fillColor: \'' + step.args.fillColor + '\'>>; ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_MIRRORPOINT:
                    set_str = assign + 'mirrorpoint(' + step.src_ids[1] + ', ' + step.src_ids[0] + ') <<' + attrid;
                    set_str += 'fillColor: \'' + step.args.fillColor + '\'>>; ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_TANGENT:
                    if (step.args.create_point === true) {
                        sub_id = step.dest_sub_ids[2];
                        set_str = 'point(' + pn(step.args.usrCoords[1]) + ',' + pn(step.args.usrCoords[2]) + ') <<id: \'';
                        set_str += sub_id + '\', fillColor: \'' + step.args.fillColor + '\'>>; ' + sub_id + '.glide(';
                        set_str += step.src_ids[0] + '); ';
                        reset_str = 'delete ' + sub_id + '; ';
                    } else
                        sub_id = step.src_ids[0];

                    set_str += assign + 'tangent(' + sub_id + ') <<' + attrid + 'point1: <<name: \'' + step.dest_sub_ids[0];
                    set_str += '\', id: \'' + step.dest_sub_ids[0] + '\'>>, point2: <<name: \'' + step.dest_sub_ids[1];
                    set_str += '\', id: \'' + step.dest_sub_ids[1] + '\'>> >>; ';
                    reset_str = 'delete ' + step.dest_sub_ids[0] + '; ' + reset_str;
                    reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[1] + '; ' + reset_str;
                    break;

                case JXG.GENTYPE_PARALLEL:
                    if (step.args.create_point === true) {
                        sub_id = step.dest_sub_ids[1];
                        set_str = 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]) + ') <<id: \'';
                        set_str += sub_id + '\', name: \'\', visible: false, priv: true>>; ';
                        reset_str = 'delete ' + sub_id + '; ';
                    } else
                        sub_id = step.src_ids[1];

                    set_str += assign + 'parallel(' + step.src_ids[0] + ', ' + sub_id + ') <<' + attrid + 'point: <<id: \'';
                    set_str += step.dest_sub_ids[0] + '\', name: \'' + step.dest_sub_ids[0] + '\'>> >>; ';
                    reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[0] + '; ' + reset_str;
                    break;

                case JXG.GENTYPE_BISECTORLINES:
                    set_str = 'bisectorlines(' + step.src_ids[0] + ', ' + step.src_ids[1] + ') <<line1: <<id: \'';
                    set_str = set_str + step.dest_sub_ids[2] + '\', point1: <<id: \'' + step.dest_sub_ids[1];
                    set_str += '\', name: \'' + step.dest_sub_ids[1] + '\'>>, point2: <<id: \'' + step.dest_sub_ids[0];
                    set_str += '\', name: \'' + step.dest_sub_ids[0] + '\'>>>>, line2: <<id: \'' + step.dest_sub_ids[5];
                    set_str += '\', point1: <<id: \'' + step.dest_sub_ids[4] + '\', name: \'' + step.dest_sub_ids[4];
                    set_str += '\'>>, point2: <<id: \'' + step.dest_sub_ids[3] + '\', name: \'' + step.dest_sub_ids[3];
                    set_str += '\'>>>>>>; ';
                    reset_str = 'delete ' + step.dest_sub_ids[5] + '; delete ' + step.dest_sub_ids[4] + '; delete ';
                    reset_str += step.dest_sub_ids[3] + '; delete ' + step.dest_sub_ids[2] + '; delete ';
                    reset_str += step.dest_sub_ids[1] + '; delete ' + step.dest_sub_ids[0] + '; ';
                    break;

                case JXG.GENTYPE_PERPENDICULAR_BISECTOR:
                    if (step.args.create_line === true) {
                        sub_id = step.dest_sub_ids[2];
                        set_str = 'line(' + step.src_ids[0] + ', ' + step.src_ids[1] + ') <<id: \'' + sub_id;
                        set_str += '\', visible: true>>; ';
                        reset_str = 'delete ' + sub_id + '; ';
                    } else
                        sub_id = step.src_ids[2];

                    set_str += 'midpoint(' + step.src_ids[0] + ', ' + step.src_ids[1] + ') <<id: \'' + step.dest_sub_ids[0];
                    set_str += '\', fillColor: \'' + step.args.fillColor + '\'>>; ';
                    set_str += assign + 'normal(' + step.dest_sub_ids[0] + ', ' + sub_id + ') <<' + attrid;
                    set_str += ' point: <<id: \'' + step.dest_sub_ids[1] + '\', name: \'' + step.dest_sub_ids[1];
                    set_str += '\'>> >>; ';
                    reset_str = 'delete ' + step.dest_sub_ids[0] + '; ' + reset_str;
                    reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[1] + '; ' + reset_str;
                    break;

                case JXG.GENTYPE_BISECTOR:
                    if (step.args.create_point === true) {
                        // TODO: use "if (options.useGlider) {"
                        
                        // Projection to first line
                        pid1 = step.dest_sub_ids[1];
                        set_str = 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]) + ') ';
                        set_str += '<<id:\'' + pid1 + '\', ';
                        set_str += 'name:\'\', priv:true, visible:false >>; ';
                        set_str += pid1 + '.glide(' + step.src_ids[0] + ');\n';
                        reset_str = 'delete ' + pid1 + '; ';

                        // Projection to second line
                        pid2 = step.dest_sub_ids[2];
                        set_str += 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]) + ') ';
                        set_str += '<<id:\'' + pid2 + '\', ';
                        set_str += 'name:\'\', priv:true, visible:false >>; ';
                        set_str += pid2 + '.glide(' + step.src_ids[1] + ');\n';
                        reset_str += 'delete ' + pid2 + '; ';

                        if (step.args.create_intersection) {
                            // intersection point
                            pid3 = step.dest_sub_ids[3];
                            set_str += 'intersection(' + step.src_ids[0] + ', ' + step.src_ids[1] + ', 0) ';
                            set_str += '<<id:\'' + pid3 + '\', fillColor: \'' + step.args.fillColor + '\', ';
                            set_str += 'name:\'\', priv:true, visible:false >>; \n';
                            reset_str += 'delete ' + pid3 + '; ';
                        } else {
                            pid3 = step.src_ids[2];
                        }
                        set_str += assign + 'bisector(' + pid1 + ', ' + pid3 + ', ' + pid2 + ') ';
                        set_str += '<<' + attrid + 'point: <<id: \'' + step.dest_sub_ids[0] + '\', priv: true, name: \'';
                        set_str += step.dest_sub_ids[0] + '\'>> >>; ';
                        reset_str += 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[0] + '; ';
                    } else {
                        set_str = assign + 'bisector(' + step.src_ids[1] + ', ' + step.src_ids[2] + ', ' + step.src_ids[0];
                        set_str += ') <<' + attrid + 'point: <<id: \'' + step.dest_sub_ids[0] + '\', priv: true, name: \'';
                        set_str += step.dest_sub_ids[0] + '\'>>>>; ';
                        reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[0] + '; ';
                    }
                    break;

                case JXG.GENTYPE_NORMAL:
                    if (step.args.create_point === true) {
                        sub_id = step.dest_sub_ids[1];
                        set_str = 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]);
                        set_str += ') <<id: \'' + sub_id + '\', name: \'\', visible: false, priv: true>>; ';
                        reset_str = 'delete ' + sub_id + '; ';
                    } else
                        sub_id = step.src_ids[1];

                    set_str += assign + 'normal(' + sub_id + ', ' + step.src_ids[0] + ') <<' + attrid;
                    set_str += 'point: <<id: \'' + step.dest_sub_ids[0] + '\', name: \'' + step.dest_sub_ids[0];
                    set_str += '\'>> >>; ';
                    reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[0] + '; ' + reset_str;
                    break;

                case JXG.GENTYPE_POINT:
                    set_str = assign + 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]);
                    set_str += ')' + ( options.useSymbols ? '' : ' <<id: \'' + step.dest_id + '\'>>') + ';';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_GLIDER:
                    if (options.useGlider) {
                        set_str = assign + 'glider(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]);
                        set_str += ', ' + step.src_ids[0] + ')';
                        set_str += ( options.useSymbols ? '' : '<<id: \'' + step.dest_id + '\'>>') + ';';
                    } else {
                        set_str = assign + 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]);
                        set_str += ') <<' + attrid + ' fillColor: \'' + step.args.fillColor + '\'>>; ' + step.dest_id;
                        set_str += '.glide(' + step.src_ids[0] + '); ';
                    }
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_INTERSECTION:
                    set_str = assign + 'intersection(' + step.src_ids[0] + ', ' + step.src_ids[1] + ', ' + step.args.choice;
                    set_str += ') <<' + attrid + ' fillColor: \'' + step.args.fillColor + '\'>>; ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_CIRCLE:
                    reset_str = 'delete ' + step.dest_sub_ids[0] + '; ';
/*
                    if (step.args.create_point === true || step.args.create_midpoint === true) {

                        if (step.args.create_point === true) {
                            set_str = 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]);
                            set_str += ') <<id: \'' + step.dest_sub_ids[0] + '\', priv: false>>; ';
                        } else {
                            set_str = 'midpoint(' + step.src_ids[0] + ', ' + step.src_ids[1] + ') <<id: \'';
                            set_str += step.dest_sub_ids[0] + '\', name: \'\', visible: true>>; ';
                        }

                        set_str += assign + 'circle(' + step.dest_sub_ids[0] + ', ' + step.src_ids[0] + ') <<' + attrid;
                        set_str += ' fillOpacity: ' + JXG.Options.opacityLevel + ' >>; ';
                        reset_str = 'delete ' + step.dest_id + '; ' + reset_str;
*/                        
                    if (step.args.create_point === true) {
                        set_str = 'point(' + pn(step.args.usrCoords[1]) + ', ' + pn(step.args.usrCoords[2]);
                        set_str += ') <<id: \'' + step.dest_sub_ids[0] + '\', priv: false>>; ';

                        set_str += assign + 'circle(' + step.dest_sub_ids[0] + ', ' + step.src_ids[0] + ') <<' + attrid;
                        set_str += ' fillOpacity: ' + JXG.Options.opacityLevel + ' >>; ';
                        reset_str = 'delete ' + step.dest_id + '; ' + reset_str;
                    } else if (step.args.create_by_radius === true) {
                        set_str = 'point(' + pn(step.args.x) + ', ' + pn(step.args.y) + ') <<id: \'' + step.dest_sub_ids[0];
                        set_str += '\', name: \'\', withLabel: true, visible: true, priv: false>>; ';
                        set_str += step.dest_sub_ids[0] + '.visible = true; ';
                        set_str += assign + 'circle(\'' + step.dest_sub_ids[0] + '\', ' + pn(step.args.r) + ') <<' + attrid;
                        set_str += ' fillOpacity: ' + JXG.Options.opacityLevel + '>>; ';
                        reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[0] + '; ';
                    } else {
                        set_str = assign + 'circle(' + step.src_ids[0] + ', ' + step.src_ids[1] + ', ' + step.src_ids[2];
                        set_str += ') <<center: <<id: \'' + step.dest_sub_ids[0] + '\', name: \'' + step.dest_sub_ids[0];
                        set_str += '\', visible: true>>, ' + attrid + ' fillOpacity: ' + JXG.Options.opacityLevel + '>>; ';
                        reset_str = 'delete ' + step.dest_id + '; ' + reset_str;
                    }

                    break;

                case JXG.GENTYPE_CIRCLE2POINTS:
                    if (step.args.create_two_points === true) {
                        set_str = 'point(' + pn(step.args.x1) + ', ' + pn(step.args.y1) + ') <<id: \'' + step.dest_sub_ids[0];
                        set_str += '\'>>; ';
                        set_str += 'point(' + pn(step.args.x2) + ', ' + pn(step.args.y2) + ') <<id: \'';
                        set_str += step.dest_sub_ids[1] + '\'>>; ';
                        set_str += assign + 'circle(' + step.dest_sub_ids[0] + ', ' + step.dest_sub_ids[1] + ') <<' + attrid;
                        set_str += ' fillOpacity: ' + JXG.Options.opacityLevel + '>>; ';
                        reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[1] + '; delete ';
                        reset_str += step.dest_sub_ids[0] + '; ';
                    } else if (step.args.create_point === true) {
                        set_str = 'point(' + pn(step.args.x) + ', ' + pn(step.args.y) + ') <<id: \'' + step.dest_sub_ids[0];
                        set_str += '\'>>; ';
                        set_str += assign + 'circle(' + step.dest_sub_ids[0] + ', ' + step.src_ids[0] + ') <<' + attrid;
                        set_str += ' fillOpacity: ' + JXG.Options.opacityLevel + '>>; ';
                        reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[0] + '; ';
                    } else if (step.args.create_by_radius === true) {
                        set_str = assign + 'circle(' + step.src_ids[0] + ', ' + step.args.r + ') <<' + attrid;
                        set_str += ' fillOpacity: ' + JXG.Options.opacityLevel + '>>; ';
                        reset_str = 'delete ' + step.dest_id + '; ';
                    } else {
                        set_str = assign + 'circle(' + step.src_ids[0] + ', ' + step.src_ids[1] + ') <<' + attrid;
                        set_str += ' fillOpacity: ' + JXG.Options.opacityLevel + '>>; ';
                        reset_str = 'delete ' + step.dest_id + '; ';
                    }

                    break;

                case JXG.GENTYPE_LINE:
                    k = 0;
                    j = 0;

                    if (step.args.create_point1) {
                        pid1 = step.dest_sub_ids[k++];
                        str1 = [];
                        for (i = 0; i < step.args.p1.length; i++)
                            str1[i] = pn(step.args.p1[i]);

                        set_str = 'point(' + str1.join(', ') + ') <<id: \'' + pid1 + '\', name: \'\', visible: false, ';
                        set_str += 'priv: true>>; ';
                        reset_str = 'delete ' + pid1 + '; ';
                    } else
                        pid1 = step.src_ids[j++];

                    if (step.args.create_point2) {
                        pid2 = step.dest_sub_ids[k++];
                        str1 = [];
                        for (i = 0; i < step.args.p2.length; i++)
                            str1[i] = pn(step.args.p2[i]);

                        set_str += 'point(' + str1.join(', ') + ') <<id: \'' + pid2 + '\', name: \'\', visible: false, ';
                        set_str += 'priv: true>>; ';
                        reset_str = 'delete ' + pid2 + '; ' + reset_str;
                    } else
                        pid2 = step.src_ids[j++];

                    str = 'line';
                    str1 = '';

                    // the line's parents
                    str2 = pid1 + ', ' + pid2;

                    // if we want a truly free line
                    if (step.args.create_point1 && step.args.create_point2 && options.freeLine) {
                        // forget the points
                        set_str = '';
                        reset_str = '';

                        // use the stdform instead
                        if (step.args.p1.length === 2)
                            step.args.p1.unshift(1);

                        if (step.args.p2.length === 2)
                            step.args.p2.unshift(1);

                        str2 = JXG.Math.crossProduct(step.args.p1, step.args.p2);
                        for (i = 0; i < str2.length; i++)
                            str2[i] = pn(str2[i]);

                        str2 = str2.join(', ');
                    }

                    if (!step.args.first && !step.args.last)
                        str = 'segment';
                    else {
                        if (!step.args.first)
                            str1 = 'straightFirst: ' + step.args.first;

                        if (!step.args.last)
                            str1 = 'straightLast: ' + step.args.last;

                        if (str1.length > 0 && !options.useSymbols)
                            str1 += ', ';
                    }

                    // this is a corner case, we have to get rid of the ',' at the end
                    // simple solution: rebuild attrid
                    if (!options.useSymbols)
                        attrid = ' id: \'' + step.dest_id + '\' ';

                    set_str += assign + str + '(' + str2 + ')';
                    set_str += (str1.length + attrid.length > 0 ? ' <<' + str1 + attrid + '>>' : '') + ';';
                    reset_str = 'delete ' + step.dest_id + '; ' + reset_str;

                    break;

                case JXG.GENTYPE_TRIANGLE:
                    for (i = 0; i < step.args.create_point.length; i++)
                        if (step.args.create_point[i] === true) {
                            set_str += 'point(' + pn(step.args.coords[i].usrCoords[1]) + ', ';
                            set_str += pn(step.args.coords[i].usrCoords[2]) + ') <<id: \'' + step.dest_sub_ids[i];
                            set_str += '\'>>; ';
                        }

                    for (i = 0; i < step.dest_sub_ids.length; i++)
                        if (step.dest_sub_ids[i] !== 0)
                            reset_str = 'delete ' + step.dest_sub_ids[i] + '; ' + reset_str;

                    reset_str = 'delete ' + step.dest_id + '; ' + reset_str;

                    set_str += assign + 'polygon(';

                    for (i = 0; i < step.src_ids.length; i++) {
                        set_str += step.src_ids[i];
                        if (i < step.src_ids.length - 1)
                            set_str += ', ';
                    }

                    for (i = 0; i < 3; i++) {
                        if (step.dest_sub_ids[i] !== 0) {
                            if (step.src_ids.length > 0 || i > 0)
                                set_str += ', ';
                            set_str += step.dest_sub_ids[i];
                        }
                    }

                    set_str += ') <<borders: <<ids: [ \'' + step.dest_sub_ids[3] + '\', \'' + step.dest_sub_ids[4];
                    set_str += '\', \'' + step.dest_sub_ids[5] + '\' ]>>, ' + attrid + ' fillOpacity: ';
                    set_str += JXG.Options.opacityLevel + ', hasInnerPoints:true, scalable:true>>; ';
                    break;

                case JXG.GENTYPE_QUADRILATERAL:
                    for (i = 0; i < step.args.create_point.length; i++)
                        if (step.args.create_point[i] === true) {
                            set_str += 'point(' + pn(step.args.coords[i].usrCoords[1]) + ', ';
                            set_str += pn(step.args.coords[i].usrCoords[2]) + ') <<id: \'' + step.dest_sub_ids[i];
                            set_str += '\'>>; ';
                        }

                    for (i = 0; i < step.dest_sub_ids.length; i++)
                        if (step.dest_sub_ids[i] !== 0)
                            reset_str = 'delete ' + step.dest_sub_ids[i] + '; ' + reset_str;

                    reset_str = 'delete ' + step.dest_id + '; ' + reset_str;

                    set_str += assign + 'polygon(';

                    for (i = 0; i < step.src_ids.length; i++) {
                        set_str += step.src_ids[i];
                        if (i < step.src_ids.length - 1)
                            set_str += ', ';
                    }

                    set_str += ') <<borders: <<ids: [ \'' + step.dest_sub_ids[4] + '\', \'' + step.dest_sub_ids[5];
                    set_str += '\', \'';
                    set_str += step.dest_sub_ids[6] + '\', \'' + step.dest_sub_ids[7] + '\' ]>>, ' + attrid;
                    set_str += ' fillOpacity: ';
                    set_str += JXG.Options.opacityLevel + ', hasInnerPoints:true, scalable:true>>; ';
                    break;

                case JXG.GENTYPE_TEXT:
                    set_str = assign + 'text(' + pn(step.args.x) + ', ' + pn(step.args.y) + ', ' + step.args.str + ') <<';
                    set_str += attrid + ' name: \'' + step.dest_id + '\'>>; ' + step.dest_id + '.setText(' + step.args.str;
                    set_str += '); ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_POLYGON:
                    set_str = assign + 'polygon(';

                    for (i = 0; i < step.src_ids.length; i++) {
                        set_str += step.src_ids[i];
                        if (i != step.src_ids.length - 1)
                            set_str += ', ';
                    }

                    set_str += ') <<borders: <<ids: [ \'';

                    for (i = 0; i < step.dest_sub_ids.length; i++) {
                        set_str += step.dest_sub_ids[i];
                        if (i < step.dest_sub_ids.length - 1)
                            set_str += '\', \'';
                    }

                    set_str += '\' ]>>, ' + attrid + ' fillOpacity: ' + JXG.Options.opacityLevel + ' >>; ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_REGULARPOLYGON:
                    set_str = assign + 'regularpolygon(' + step.src_ids[0] + ', ' + step.src_ids[1] + ', ';
                    set_str += step.args.corners + ') <<borders: <<ids: [ ';

                    for (i = 0; i < step.args.corners; i++) {
                        set_str += '\'' + step.dest_sub_ids[i] + '\'';
                        if (i != step.args.corners - 1)
                            set_str += ', ';
                        reset_str = 'delete ' + step.dest_sub_ids[i] + '; ' + reset_str;
                    }

                    set_str += ' ]>>, vertices: <<ids: [ ';

                    for (i = 0; i < step.args.corners - 2; i++) {
                        set_str += '\'' + step.dest_sub_ids[i + parseInt(step.args.corners)] + '\'';
                        if (i != step.args.corners - 3)
                            set_str += ', ';
                        reset_str = 'delete ' + step.dest_sub_ids[i + parseInt(step.args.corners)] + '; ' + reset_str;
                    }

                    set_str += ' ]>>, ' + attrid + ' fillOpacity: ' + JXG.Options.opacityLevel + ' >>; ';
                    reset_str = 'delete ' + step.dest_id + '; ' + reset_str;
                    break;

                case JXG.GENTYPE_SECTOR:
                    set_str = assign + 'sector(' + step.src_ids[0] + ', ' + step.src_ids[1] + ', ' + step.src_ids[2];
                    set_str += ') <<';
                    set_str += attrid + ' name: \'' + step.dest_id + '\', fillOpacity: ' + JXG.Options.opacityLevel;
                    set_str += '>>; ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_ANGLE:
                    set_str = assign + 'angle(' + step.src_ids[0] + ', ' + step.src_ids[1] + ', ' + step.src_ids[2] + ') ';
                    set_str += '<<radiuspoint: << priv:true, id: \'' + step.dest_sub_ids[0] + '\', name: \'' + step.dest_sub_ids[0];
                    set_str += '\'>>, pointsquare: << priv:true, id: \'' + step.dest_sub_ids[1] + '\', name: \'' + step.dest_sub_ids[1];
                    set_str += '\'>>, dot: << priv:true, id: \'' + step.dest_sub_ids[2] + '\', name: \'' + step.dest_sub_ids[2];
                    set_str += '\'>>, ';
                    set_str += attrid + ' fillOpacity: ' + JXG.Options.opacityLevel + '>>; ';
                    reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[2] + '; delete ';
                    reset_str += step.dest_sub_ids[1];
                    reset_str += '; delete ' + step.dest_sub_ids[0] + '; ';
                    break;

                case JXG.GENTYPE_PLOT:
                    set_str = assign + step.args.plot_type + '(' + step.args.func + ') <<';

                    if (step.args.isPolar)
                        set_str += 'curveType: \'polar\', ';

                    set_str += attrid + ' name:\'' + step.dest_id + '\'>>; ';
                    reset_str = 'delete ' + step.dest_id + '; ';
                    break;

                case JXG.GENTYPE_SLIDER:
                    set_str = assign + 'slider([' + pn(step.args.x1) + ', ' + pn(step.args.y1) + '], [' + pn(step.args.x2);
                    set_str += ', ' + pn(step.args.y2) + '], [' + pn(step.args.start) + ', ' + pn(step.args.ini) + ', ';
                    set_str += pn(step.args.end) + ']) <<' + attrid + ' name: \'' + step.dest_id + '\', baseline: <<id: \'';
                    set_str += step.dest_sub_ids[0] + '\', name: \'' + step.dest_sub_ids[0] + '\'>>, highline: <<id: \'';
                    set_str += step.dest_sub_ids[1] + '\', name: \'' + step.dest_sub_ids[1] + '\'>>, point1: <<id: \'';
                    set_str += step.dest_sub_ids[2] + '\', name: \'' + step.dest_sub_ids[2] + '\'>>, point2: <<id: \'';
                    set_str += step.dest_sub_ids[3] + '\', name: \'' + step.dest_sub_ids[3] + '\'>>, label: <<id: \'';
                    set_str += step.dest_sub_ids[4] + '\', name: \'' + step.dest_sub_ids[4] + '\'>>>>; ';

                    reset_str = 'delete ' + step.dest_id + '; delete ' + step.dest_sub_ids[4] + '; delete ';
                    reset_str += step.dest_sub_ids[3] + '; delete ' + step.dest_sub_ids[2] + '; delete ';
                    reset_str += step.dest_sub_ids[1] + '; delete ';
                    reset_str += step.dest_sub_ids[0] + '; ';
                    break;

                case JXG.GENTYPE_DELETE:

                    arr = [];
                    ctx_set_str = [];
                    ctx_reset_str = [];

                    for (i = 0; i < step.args.steps.length; i++) {
                        if (step_log[step.args.steps[i]].type > 50) {
                            arr = this.generateJCodeMeta(step_log[step.args.steps[i]], board);
                        } else {
                            arr = this.generateJCode(step_log[step.args.steps[i]], board, step_log);
                        }

                        if (arr[2].trim() !== '') {
                            set_str = arr[2] + set_str;
                        }
                        if (JXG.isFunction(arr[3])) {
                            ctx_set_str.unshift(arr[3]);
                        }
                        if (arr[0].trim() !== '') {
                            reset_str += arr[0];
                        }
                        if (JXG.isFunction(arr[1])) {
                            ctx_reset_str.push(arr[1]);
                        }
                    }

                    break;

                case JXG.GENTYPE_COPY:
                    copy_log = [];

                    // Adapt the steps to the new IDs

                    for (el in step.args.steps) {

                        if (step.args.steps.hasOwnProperty(el)) {
                            step2 = JXG.deepCopy(step_log[step.args.steps[el]]);

                            if (step2.type == JXG.GENTYPE_COPY) {

                                for (i = 0; i < step2.args.map.length; i++)
                                    for (j = 0; j < step.args.map.length; j++)
                                        if (step2.args.map[i].copy == step.args.map[j].orig)
                                            step2.args.map[i].copy = step.args.map[j].copy;

                                step2 = JXG.SketchReader.replaceStepDestIds(step2, step2.args.map);
                            } else
                                step2 = JXG.SketchReader.replaceStepDestIds(step2, step.args.map);

                            copy_log.push(step2);
                        }
                    }

                    for (i = 0; i < copy_log.length; i++) {

                        if (copy_log[i].type > 50)
                            arr = this.generateJCodeMeta(copy_log[i], board);
                        else
                            arr = this.generateJCode(copy_log[i], board, step_log);

                        if (arr[0].trim() !== '')
                            set_str += arr[0];
                        if (JXG.isFunction(arr[1]))
                            ctx_set_str.push(arr[1]);
                        if (arr[2].trim() !== '')
                            reset_str = arr[2] + reset_str;
                        if (JXG.isFunction(arr[3]))
                            ctx_reset_str.unshift(arr[3]);
                    }

                    // Apply the offset-translation to the free points of the copy

                    if (step.args.dep_copy) {

                        for (i = 0; i < step.args.map.length; i++) {
                            if (getObject(step.args.map[i].orig).elementClass == JXG.OBJECT_CLASS_POINT) {
                                set_str += step.args.map[i].copy;
                                set_str += '.X = function() { return (' + step.args.map[i].orig + '.X() - ';
                                set_str += pn(step.args.x) + '); }; ';
                                set_str += step.args.map[i].copy;
                                set_str += '.Y = function() { return (' + step.args.map[i].orig + '.Y() - ';
                                set_str += pn(step.args.y) + '); }; ';
                            }
                        }

                    } else {

                        for (i = 0; i < step.args.free_points.length; i++) {
                            xstart = getObject(step.args.free_points[i].orig).coords.usrCoords[1];
                            ystart = getObject(step.args.free_points[i].orig).coords.usrCoords[2];

                            set_str += step.args.free_points[i].copy + '.X = function() { return ';
                            set_str += pn(xstart - step.args.x) + '; }; ';
                            set_str += step.args.free_points[i].copy + '.Y = function() { return ';
                            set_str += pn(ystart - step.args.y) + '; }; ';
                            set_str += step.args.free_points[i].copy + '.free(); ';
                        }
                    }

                    for (j = 0; j < step.args.map.length; j++) {
                        el = getObject(step.args.map[j].orig);

                        // Check if a radius-defined circle should be copied
                        if (el.type == JXG.OBJECT_TYPE_CIRCLE && el.point2 == null) {
                            // Make the radius of the circle copy depend on the original circle's radius
                            set_str += step.args.map[j].copy + '.setRadius(function () { return ';
                            set_str += step.args.map[j].orig + '.radius(); }); ';
                        }
                    }

                    break;

                case JXG.GENTYPE_ABLATION:

                    xstart = getObject(step.src_ids[0]).coords.usrCoords[1];
                    ystart = getObject(step.src_ids[0]).coords.usrCoords[2];

                    set_str = 'point(' + pn(xstart - step.args.x) + ', ' + pn(ystart - step.args.y) + ') <<id: \'';
                    set_str += step.dest_sub_ids[0] + '\'>>; ';
                    set_str += 'circle(' + step.dest_sub_ids[0] + ', 1) <<id: \'' + step.dest_sub_ids[1];
                    set_str += '\', fillOpacity: ' + JXG.Options.opacityLevel + ', strokeColor: \'#888888\', visible: true>>; ';

                    if (step.args.fids.length == 1)
                        step.args.func = step.args.fids[0] + '.radius()';
                    else
                        step.args.func = 'dist(' + step.args.fids[0] + ', ' + step.args.fids[1] + ')';

                    set_str += step.dest_sub_ids[1] + '.setRadius(function() { return ' + step.args.func + '; }); ';

                    if (step.args.migrate != 0 && step.args.migrate != -1)
                        set_str += '$board.migratePoint(' + step.dest_sub_ids[0] + ', ' + step.args.migrate + '); ';
                    else
                        reset_str += 'delete ' + step.dest_sub_ids[0] + '; '; // a de-migration function is missing ...

                    reset_str = 'delete ' + step.dest_sub_ids[1] + '; ' + reset_str;

                    break;

                case JXG.GENTYPE_MIGRATE:

                    set_str += '$board.migratePoint(' + step.src_ids[0] + ', ' + step.dest_id + '); ';
                    reset_str += 'delete ' + step.dest_id + '; '; // as above: missing de-migration ...

                    break;

                case JXG.GENTYPE_TRANSFORM:

                    set_str = step.dest_sub_ids[0] + ' = transform(' + step.args.tmat + ') <<type: \'generic\'>>; ';
                    set_str += 'point(' + step.src_ids[0] + ', ' + step.dest_sub_ids[0] + ') <<id: \'' + step.dest_id;
                    set_str += '\', visible: true>>; ';

                    reset_str = 'delete ' + step.dest_id + '; ';
                    reset_str += 'delete ' + step.dest_sub_ids[0] + '; ';

                    break;

                case JXG.GENTYPE_MOVEMENT:
                    if (step.args.obj_type == JXG.OBJECT_TYPE_LINE) {
                        set_str = step.src_ids[0] + '.move([' + pn(step.args.coords[0].usrCoords[0]) + ', ';
                        set_str += pn(step.args.coords[0].usrCoords[1]) + ', ' + pn(step.args.coords[0].usrCoords[2]) + ']); ';
                        reset_str = step.src_ids[0] + '.move([' + step.args.zstart[0] + ', ' + step.args.xstart[0] + ', ';
                        reset_str += step.args.ystart[0] + ']); ';

                        set_str += step.src_ids[1] + '.move([' + pn(step.args.coords[1].usrCoords[0]) + ', ';
                        set_str += pn(step.args.coords[1].usrCoords[1]) + ', ' + pn(step.args.coords[1].usrCoords[2]) + ']); ';
                        reset_str += step.src_ids[1] + '.move([' + step.args.zstart[1] + ', ' + step.args.xstart[1] + ', ';
                        reset_str += step.args.ystart[1] + ']); ';

                    } else if (step.args.obj_type == JXG.OBJECT_TYPE_CIRCLE) {
                        set_str = step.src_ids[0] + '.move([' + pn(step.args.coords[0].usrCoords[1]) + ', ';
                        set_str += pn(step.args.coords[0].usrCoords[2]) + ']); ';
                        reset_str = step.src_ids[0] + '.move([' + step.args.xstart + ', ' + step.args.ystart + ']); ';

                        if (step.args.has_point2) {
                            set_str += step.src_ids[1] + '.move([' + pn(step.args.coords[1].usrCoords[1]) + ', ';
                            set_str += pn(step.args.coords[1].usrCoords[2]) + ']); ';
                            reset_str += step.src_ids[1] + '.move([' + step.args.old_p2x + ', ' + step.args.old_p2y;
                            reset_str += ']); ';
                        }

                    } else if (step.args.obj_type == JXG.OBJECT_TYPE_GLIDER) {
                        set_str = step.src_ids[0] + '.setPosition(' + pn(step.args.position) + '); ';
                        reset_str = step.src_ids[0] + '.setPosition(' + step.args.xstart + '); ';

                    } else if (step.args.obj_type == JXG.OBJECT_TYPE_POLYGON) {
                        set_str = reset_str = "";

                        for (i = 0; i < step.src_ids.length; i++) {
                            set_str += step.src_ids[i] + '.move([' + pn(step.args.coords[i].usrCoords[1]) + ', ';
                            set_str += pn(step.args.coords[i].usrCoords[2]) + ']); ';
                            reset_str += step.src_ids[i] + '.move([' + step.args.xstart[i] + ', ' + step.args.ystart[i];
                            reset_str += ']); ';
                        }
                    } else {
                        set_str = step.src_ids[0] + '.move([' + pn(step.args.coords[0].usrCoords[1]) + ', ';
                        set_str += pn(step.args.coords[0].usrCoords[2]) + ']); ';
                        reset_str = step.src_ids[0] + '.move([' + step.args.xstart + ', ' + step.args.ystart + ']); ';
                    }

                    break;

                default:
                    return;
            }

            return [ set_str, ctx_set_str, reset_str, ctx_reset_str ];
        },

        replaceStepDestIds: function (step, id_map) {
            var i, j, copy_ids = [];

            for (i = 0; i < id_map.length; i++) {
                copy_ids.push(id_map[i].copy);

                if (step.dest_id == id_map[i].orig)
                    step.dest_id = id_map[i].copy;

                for (j = 0; j < step.dest_sub_ids.length; j++) {
                    if (step.dest_sub_ids[j] == id_map[i].orig) {
                        step.dest_sub_ids[j] = id_map[i].copy;
                    }
                }

                for (j = 0; j < step.src_ids.length; j++) {
                    if (step.src_ids[j] == id_map[i].orig) {
                        step.src_ids[j] = id_map[i].copy;
                    }
                }
            }

            for (j = 0; j < step.dest_sub_ids.length; j++) {
                if (!JXG.isInArray(copy_ids, step.dest_sub_ids[j])) {
                    step.dest_sub_ids[j] = this.id();
                }
            }

            step.src_ids = JXG.uniqueArray(step.src_ids);
            step.dest_sub_ids = JXG.uniqueArray(step.dest_sub_ids);

            return step;
        },

        readSketch: function (str, board) {
            var i, j, arr, json_obj, unzipped, meta, constr;

            unzipped = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str)).unzip();

            if (!JXG.exists(unzipped[0])) {
                return '';
            }

            unzipped = JXG.Util.utf8Decode(unzipped[0][0]);
            constr = JSON.parse(unzipped);

            for (i = 0; i < constr.length - 1; i++) {

                if (constr[i].type == 0)
                    continue;

                // fix for files created with the beta version
                if (constr[i].type == JXG.GENTYPE_CTX_VISIBILITY && constr[i].args.isGrid) {
                    //constr[i] = { type: 0, src_ids: [], dest_sub_ids: [], dest_id: 0 };
                    continue;
                }

                if (constr[i].type == JXG.GENTYPE_GRID) {
                    //constr[i] = { type: 0, src_ids: [], dest_sub_ids: [], dest_id: 0 };
                    continue;
                }
                // end of fix
/*
                if (constr[i].type == 100) // Obsolete fix
                    constr[i].type = JXG.GENTYPE_MOVEMENT;

                if (constr[i].type == JXG.GENTYPE_MOVEMENT) {

                    for (j=i+1; j<constr.length-1; j++) {
                        if (constr[j].type == JXG.GENTYPE_MOVEMENT && JXG.Draw.areEqual(constr[i].src_ids,
                            constr[j].src_ids)) {
                            constr[i] = { type: 0, src_ids: [], dest_sub_ids: [], dest_id: 0 };
                            break;
                        }
                    }

                    if (j < constr.length-1)
                        continue;
                }
*/
                if (constr[i].type == 27) // Obsolete fix
                    constr[i].type = JXG.GENTYPE_DELETE;

                if (constr[i].type == 31) // Obsolete fix
                    constr[i].type = JXG.GENTYPE_ABLATION;

                if (constr[i] > 50)
                    arr = this.generateJCodeMeta(constr[i], board);
                else
                    arr = this.generateJCode(constr[i], board, constr);
                    
                board.jc.parse(arr[0], true);
            }

            meta = constr.pop();

            // not yet :(
            //if (meta.axisVisible)
            //if (meta.gridVisible)

            arr = meta.boundingBox; // bounding box
            board.setBoundingBox(arr);

            // these might be important in the future
            //GUI.transformation = meta.transformation; // transformation matrices (rotations, ...)
            //GUI.restore_state = meta.restoreState; // restore states

            board.options.grid.snapToGrid = !meta.snapToGrid;
            board.options.point.snapToGrid = !meta.snapToGrid;
            board.options.point.snapToPoints = !meta.snapToPoints;

            return '';
        }
    }
});
