Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"shapes.min.js","sources":["../src/shapes.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/* eslint max-depth: [\"error\", 8] */\n\n/**\n * Library of classes for handling simple shapes.\n *\n * These classes can represent shapes, let you alter them, can go to and from a string\n * representation, and can give you an SVG representation.\n *\n * @module qtype_ddmarker/shapes\n * @copyright  2018 The Open University\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(function() {\n\n    \"use strict\";\n\n    /**\n     * A point, with x and y coordinates.\n     *\n     * @param {int} x centre X.\n     * @param {int} y centre Y.\n     * @constructor\n     */\n    function Point(x, y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    /**\n     * Standard toString method.\n     * @returns {string} \"x;y\";\n     */\n    Point.prototype.toString = function() {\n        return this.x + ',' + this.y;\n    };\n\n    /**\n     * Move a point\n     * @param {int} dx x offset\n     * @param {int} dy y offset\n     */\n    Point.prototype.move = function(dx, dy) {\n        this.x += dx;\n        this.y += dy;\n    };\n\n    /**\n     * Return a new point that is a certain position relative to this one.\n     *\n     * @param {(int|Point)} offsetX if a point, offset by this points coordinates, else and int x offset.\n     * @param {int} [offsetY] used if offsetX is an int, the corresponding y offset.\n     * @return {Point} the new point.\n     */\n    Point.prototype.offset = function(offsetX, offsetY) {\n        if (offsetX instanceof Point) {\n            offsetY = offsetX.y;\n            offsetX = offsetX.x;\n        }\n        return new Point(this.x + offsetX, this.y + offsetY);\n    };\n\n    /**\n     * Make a point from the string representation.\n     *\n     * @param {String} coordinates \"x,y\".\n     * @return {Point} the point. Throws an exception if input is not valid.\n     */\n    Point.parse = function(coordinates) {\n        var bits = coordinates.split(',');\n        if (bits.length !== 2) {\n            throw new Error(coordinates + ' is not a valid point');\n        }\n        return new Point(Math.round(bits[0]), Math.round(bits[1]));\n    };\n\n\n    /**\n     * Shape constructor. Abstract class to represent the different types of drop zone shapes.\n     *\n     * @param {String} [label] name of this area.\n     * @param {int} [x] centre X.\n     * @param {int} [y] centre Y.\n     * @constructor\n     */\n    function Shape(label, x, y) {\n        this.label = label;\n        this.centre = new Point(x || 0, y || 0);\n    }\n\n    /**\n     * Get the type of shape.\n     *\n     * @return {String} 'circle', 'rectangle' or 'polygon';\n     */\n    Shape.prototype.getType = function() {\n        throw new Error('Not implemented.');\n    };\n\n    /**\n     * Get the string representation of this shape.\n     *\n     * @return {String} coordinates as they need to be typed into the form.\n     */\n    Shape.prototype.getCoordinates = function() {\n        throw new Error('Not implemented.');\n    };\n\n    /**\n     * Update the shape from the string representation.\n     *\n     * @param {String} coordinates in the form returned by getCoordinates.\n     * @param {number} ratio Ratio to scale.\n     * @return {boolean} true if the string could be parsed and the shape updated, else false.\n     */\n    Shape.prototype.parse = function(coordinates, ratio) {\n        void (coordinates, ratio);\n        throw new Error('Not implemented.');\n    };\n\n    /**\n     * Move the entire shape by this offset.\n     *\n     * @param {int} dx x offset.\n     * @param {int} dy y offset.\n     * @param {int} maxX ensure that after editing, the shape lies between 0 and maxX on the x-axis.\n     * @param {int} maxY ensure that after editing, the shape lies between 0 and maxX on the y-axis.\n     */\n    Shape.prototype.move = function(dx, dy, maxX, maxY) {\n        void (maxY);\n    };\n\n    /**\n     * Move one of the edit handles by this offset.\n     *\n     * @param {int} handleIndex which handle was moved.\n     * @param {int} dx x offset.\n     * @param {int} dy y offset.\n     * @param {int} maxX ensure that after editing, the shape lies between 0 and maxX on the x-axis.\n     * @param {int} maxY ensure that after editing, the shape lies between 0 and maxX on the y-axis.\n     */\n    Shape.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) {\n        void (maxY);\n    };\n\n    /**\n     * Update the properties of this shape after a sequence of edits.\n     *\n     * For example make sure the circle radius is positive, of the polygon centre is centred.\n     */\n    Shape.prototype.normalizeShape = function() {\n        void (1); // To make CiBoT happy.\n    };\n\n    /**\n     * Get the string representation of this shape.\n     *\n     * @param {SVGElement} svg the SVG graphic to add this shape to.\n     * @return {SVGElement} SVG representation of this shape.\n     */\n    Shape.prototype.makeSvg = function(svg) {\n        void (svg);\n        throw new Error('Not implemented.');\n    };\n\n    /**\n     * Update the SVG representation of this shape.\n     *\n     * @param {SVGElement} svgEl the SVG representation of this shape.\n     */\n    Shape.prototype.updateSvg = function(svgEl) {\n        void (svgEl);\n    };\n\n    /**\n     * Make a circle similar to this shape.\n     *\n     * @return {Circle} a circle that is about the same size and position as this shape.\n     */\n    Shape.prototype.makeSimilarCircle = function() {\n        throw new Error('Not implemented.');\n    };\n\n    /**\n     * Make a rectangle similar to this shape.\n     *\n     * @return {Rectangle} a rectangle that is about the same size and position as this shape.\n     */\n    Shape.prototype.makeSimilarRectangle = function() {\n        throw new Error('Not implemented.');\n    };\n\n    /**\n     * Make a polygon similar to this shape.\n     *\n     * @return {Polygon} a polygon that is about the same size and position as this shape.\n     */\n    Shape.prototype.makeSimilarPolygon = function() {\n        throw new Error('Not implemented.');\n    };\n\n    /**\n     * Get the handles that should be offered to edit this shape, or null if not appropriate.\n     *\n     * @return {Object[]} with properties moveHandle {Point} and editHandles {Point[]}\n     */\n    Shape.prototype.getHandlePositions = function() {\n        return null;\n    };\n\n\n    /**\n     * A shape that is a circle.\n     *\n     * @param {String} label name of this area.\n     * @param {int} [x] centre X.\n     * @param {int} [y] centre Y.\n     * @param {int} [radius] radius.\n     * @constructor\n     */\n    function Circle(label, x, y, radius) {\n        x = x || 15;\n        y = y || 15;\n        Shape.call(this, label, x, y);\n        this.radius = radius || 15;\n    }\n    Circle.prototype = new Shape();\n\n    Circle.prototype.getType = function() {\n        return 'circle';\n    };\n\n    Circle.prototype.getCoordinates = function() {\n        return this.centre + ';' + Math.abs(this.radius);\n    };\n\n    Circle.prototype.makeSvg = function(svg) {\n        var svgEl = createSvgShapeGroup(svg, 'circle');\n        this.updateSvg(svgEl);\n        return svgEl;\n    };\n\n    Circle.prototype.updateSvg = function(svgEl) {\n        svgEl.childNodes[0].setAttribute('cx', this.centre.x);\n        svgEl.childNodes[0].setAttribute('cy', this.centre.y);\n        svgEl.childNodes[0].setAttribute('r', Math.abs(this.radius));\n        svgEl.childNodes[1].setAttribute('x', this.centre.x);\n        svgEl.childNodes[1].setAttribute('y', this.centre.y + 15);\n        svgEl.childNodes[1].textContent = this.label;\n    };\n\n    Circle.prototype.parse = function(coordinates, ratio) {\n        if (!coordinates.match(/^\\d+(\\.\\d+)?,\\d+(\\.\\d+)?;\\d+(\\.\\d+)?$/)) {\n            return false;\n        }\n\n        var bits = coordinates.split(';');\n        this.centre = Point.parse(bits[0]);\n        this.centre.x = this.centre.x * parseFloat(ratio);\n        this.centre.y = this.centre.y * parseFloat(ratio);\n        this.radius = Math.round(bits[1]) * parseFloat(ratio);\n        return true;\n    };\n\n    Circle.prototype.move = function(dx, dy, maxX, maxY) {\n        this.centre.move(dx, dy);\n        if (this.centre.x < this.radius) {\n            this.centre.x = this.radius;\n        }\n        if (this.centre.x > maxX - this.radius) {\n            this.centre.x = maxX - this.radius;\n        }\n        if (this.centre.y < this.radius) {\n            this.centre.y = this.radius;\n        }\n        if (this.centre.y > maxY - this.radius) {\n            this.centre.y = maxY - this.radius;\n        }\n    };\n\n    Circle.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) {\n        this.radius += dx;\n        var limit = Math.min(this.centre.x, this.centre.y, maxX - this.centre.x, maxY - this.centre.y);\n        if (this.radius > limit) {\n            this.radius = limit;\n        }\n        if (this.radius < -limit) {\n            this.radius = -limit;\n        }\n    };\n\n    /**\n     * Update the properties of this shape after a sequence of edits.\n     *\n     * For example make sure the circle radius is positive, of the polygon centre is centred.\n     */\n    Circle.prototype.normalizeShape = function() {\n        this.radius = Math.abs(this.radius);\n    };\n\n    Circle.prototype.makeSimilarRectangle = function() {\n        return new Rectangle(this.label,\n                this.centre.x - this.radius, this.centre.y - this.radius,\n                this.radius * 2, this.radius * 2);\n    };\n\n    Circle.prototype.makeSimilarPolygon = function() {\n        // We make a similar square, so if you go to and from Rectangle afterwards, it is loss-less.\n        return new Polygon(this.label, [\n                this.centre.offset(-this.radius, -this.radius), this.centre.offset(-this.radius, this.radius),\n                this.centre.offset(this.radius, this.radius), this.centre.offset(this.radius, -this.radius)]);\n    };\n\n    Circle.prototype.getHandlePositions = function() {\n        return {\n            moveHandle: this.centre,\n            editHandles: [this.centre.offset(this.radius, 0)]\n        };\n    };\n\n\n    /**\n     * A shape that is a rectangle.\n     *\n     * @param {String} label name of this area.\n     * @param {int} [x] top left X.\n     * @param {int} [y] top left Y.\n     * @param {int} [width] width.\n     * @param {int} [height] height.\n     * @constructor\n     */\n    function Rectangle(label, x, y, width, height) {\n        Shape.call(this, label, x, y);\n        this.width = width || 30;\n        this.height = height || 30;\n    }\n    Rectangle.prototype = new Shape();\n\n    Rectangle.prototype.getType = function() {\n        return 'rectangle';\n    };\n\n    Rectangle.prototype.getCoordinates = function() {\n        return this.centre + ';' + this.width + ',' + this.height;\n    };\n\n    Rectangle.prototype.makeSvg = function(svg) {\n        var svgEl = createSvgShapeGroup(svg, 'rect');\n        this.updateSvg(svgEl);\n        return svgEl;\n    };\n\n    Rectangle.prototype.updateSvg = function(svgEl) {\n        if (this.width >= 0) {\n            svgEl.childNodes[0].setAttribute('x', this.centre.x);\n            svgEl.childNodes[0].setAttribute('width', this.width);\n        } else {\n            svgEl.childNodes[0].setAttribute('x', this.centre.x + this.width);\n            svgEl.childNodes[0].setAttribute('width', -this.width);\n        }\n        if (this.height >= 0) {\n            svgEl.childNodes[0].setAttribute('y', this.centre.y);\n            svgEl.childNodes[0].setAttribute('height', this.height);\n        } else {\n            svgEl.childNodes[0].setAttribute('y', this.centre.y + this.height);\n            svgEl.childNodes[0].setAttribute('height', -this.height);\n        }\n\n        svgEl.childNodes[1].setAttribute('x', this.centre.x + this.width / 2);\n        svgEl.childNodes[1].setAttribute('y', this.centre.y + this.height / 2 + 15);\n        svgEl.childNodes[1].textContent = this.label;\n    };\n\n    Rectangle.prototype.parse = function(coordinates, ratio) {\n        if (!coordinates.match(/^\\d+(\\.\\d+)?,\\d+(\\.\\d+)?;\\d+(\\.\\d+)?,\\d+(\\.\\d+)?$/)) {\n            return false;\n        }\n\n        var bits = coordinates.split(';');\n        this.centre = Point.parse(bits[0]);\n        this.centre.x = this.centre.x * parseFloat(ratio);\n        this.centre.y = this.centre.y * parseFloat(ratio);\n        var size = Point.parse(bits[1]);\n        this.width = size.x * parseFloat(ratio);\n        this.height = size.y * parseFloat(ratio);\n        return true;\n    };\n\n    Rectangle.prototype.move = function(dx, dy, maxX, maxY) {\n        this.centre.move(dx, dy);\n        if (this.centre.x < 0) {\n            this.centre.x = 0;\n        }\n        if (this.centre.x > maxX - this.width) {\n            this.centre.x = maxX - this.width;\n        }\n        if (this.centre.y < 0) {\n            this.centre.y = 0;\n        }\n        if (this.centre.y > maxY - this.height) {\n            this.centre.y = maxY - this.height;\n        }\n    };\n\n    Rectangle.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) {\n        this.width += dx;\n        this.height += dy;\n        if (this.width < -this.centre.x) {\n            this.width = -this.centre.x;\n        }\n        if (this.width > maxX - this.centre.x) {\n            this.width = maxX - this.centre.x;\n        }\n        if (this.height < -this.centre.y) {\n            this.height = -this.centre.y;\n        }\n        if (this.height > maxY - this.centre.y) {\n            this.height = maxY - this.centre.y;\n        }\n    };\n\n    /**\n     * Update the properties of this shape after a sequence of edits.\n     *\n     * For example make sure the circle radius is positive, of the polygon centre is centred.\n     */\n    Rectangle.prototype.normalizeShape = function() {\n        if (this.width < 0) {\n            this.centre.x += this.width;\n            this.width = -this.width;\n        }\n        if (this.height < 0) {\n            this.centre.y += this.height;\n            this.height = -this.height;\n        }\n    };\n\n    Rectangle.prototype.makeSimilarCircle = function() {\n        return new Circle(this.label,\n                Math.round(this.centre.x + this.width / 2),\n                Math.round(this.centre.y + this.height / 2),\n                Math.round((this.width + this.height) / 4));\n    };\n\n    Rectangle.prototype.makeSimilarPolygon = function() {\n        return new Polygon(this.label, [\n            this.centre, this.centre.offset(0, this.height),\n            this.centre.offset(this.width, this.height), this.centre.offset(this.width, 0)]);\n    };\n\n    Rectangle.prototype.getHandlePositions = function() {\n        return {\n            moveHandle: this.centre.offset(this.width / 2, this.height / 2),\n            editHandles: [this.centre.offset(this.width, this.height)]\n        };\n    };\n\n\n    /**\n     * A shape that is a polygon.\n     *\n     * @param {String} label name of this area.\n     * @param {Point[]} [points] position of the vertices relative to (centreX, centreY).\n     *      each object in the array should have two\n     * @constructor\n     */\n    function Polygon(label, points) {\n        Shape.call(this, label, 0, 0);\n        this.points = points ? points.slice() : [new Point(10, 10), new Point(40, 10), new Point(10, 40)];\n        this.normalizeShape();\n        this.ratio = 1;\n    }\n    Polygon.prototype = new Shape();\n\n    Polygon.prototype.getType = function() {\n        return 'polygon';\n    };\n\n    Polygon.prototype.getCoordinates = function() {\n        var coordinates = '';\n        for (var i = 0; i < this.points.length; i++) {\n            coordinates += this.centre.offset(this.points[i]) + ';';\n        }\n        return coordinates.slice(0, coordinates.length - 1); // Strip off the last ';'.\n    };\n\n    Polygon.prototype.makeSvg = function(svg) {\n        var svgEl = createSvgShapeGroup(svg, 'polygon');\n        this.updateSvg(svgEl);\n        return svgEl;\n    };\n\n    Polygon.prototype.updateSvg = function(svgEl) {\n        svgEl.childNodes[0].setAttribute('points', this.getCoordinates().replace(/[,;]/g, ' '));\n        svgEl.childNodes[0].setAttribute('transform', 'scale(' + parseFloat(this.ratio) + ')');\n        svgEl.childNodes[1].setAttribute('x', this.centre.x);\n        svgEl.childNodes[1].setAttribute('y', this.centre.y + 15);\n        svgEl.childNodes[1].textContent = this.label;\n    };\n\n    Polygon.prototype.parse = function(coordinates, ratio) {\n        if (!coordinates.match(/^\\d+(\\.\\d+)?,\\d+(\\.\\d+)?(?:;\\d+(\\.\\d+)?,\\d+(\\.\\d+)?)*$/)) {\n            return false;\n        }\n\n        var bits = coordinates.split(';');\n        var points = [];\n        for (var i = 0; i < bits.length; i++) {\n            points.push(Point.parse(bits[i]));\n        }\n\n        this.points = points;\n        this.centre.x = 0;\n        this.centre.y = 0;\n        this.ratio = ratio;\n        this.normalizeShape();\n\n        return true;\n    };\n\n    Polygon.prototype.move = function(dx, dy, maxX, maxY) {\n        this.centre.move(dx, dy);\n        var bbXMin = maxX,\n            bbXMax = 0,\n            bbYMin = maxY,\n            bbYMax = 0;\n        // Computer centre.\n        for (var i = 0; i < this.points.length; i++) {\n            bbXMin = Math.min(bbXMin, this.points[i].x);\n            bbXMax = Math.max(bbXMax, this.points[i].x);\n            bbYMin = Math.min(bbYMin, this.points[i].y);\n            bbYMax = Math.max(bbYMax, this.points[i].y);\n        }\n        if (this.centre.x < -bbXMin) {\n            this.centre.x = -bbXMin;\n        }\n        if (this.centre.x > maxX - bbXMax) {\n            this.centre.x = maxX - bbXMax;\n        }\n        if (this.centre.y < -bbYMin) {\n            this.centre.y = -bbYMin;\n        }\n        if (this.centre.y > maxY - bbYMax) {\n            this.centre.y = maxY - bbYMax;\n        }\n    };\n\n    Polygon.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) {\n        this.points[handleIndex].move(dx, dy);\n        if (this.points[handleIndex].x < -this.centre.x) {\n            this.points[handleIndex].x = -this.centre.x;\n        }\n        if (this.points[handleIndex].x > maxX - this.centre.x) {\n            this.points[handleIndex].x = maxX - this.centre.x;\n        }\n        if (this.points[handleIndex].y < -this.centre.y) {\n            this.points[handleIndex].y = -this.centre.y;\n        }\n        if (this.points[handleIndex].y > maxY - this.centre.y) {\n            this.points[handleIndex].y = maxY - this.centre.y;\n        }\n    };\n\n    /**\n     * Add a new point after the given point, with the same co-ordinates.\n     *\n     * This does not automatically normalise.\n     *\n     * @param {int} pointIndex the index of the vertex after which to insert this new one.\n     */\n    Polygon.prototype.addNewPointAfter = function(pointIndex) {\n        this.points.splice(pointIndex, 0,\n                new Point(this.points[pointIndex].x, this.points[pointIndex].y));\n    };\n\n    Polygon.prototype.normalizeShape = function() {\n        var i,\n            x = 0,\n            y = 0;\n\n        if (this.points.length === 0) {\n            return;\n        }\n\n        // Computer centre.\n        for (i = 0; i < this.points.length; i++) {\n            x += this.points[i].x;\n            y += this.points[i].y;\n        }\n        x = Math.round(x / this.points.length);\n        y = Math.round(y / this.points.length);\n\n        if (x === 0 && y === 0) {\n            return;\n        }\n\n        for (i = 0; i < this.points.length; i++) {\n            this.points[i].move(-x, -y);\n        }\n        this.centre.move(x, y);\n    };\n\n    Polygon.prototype.makeSimilarCircle = function() {\n        return this.makeSimilarRectangle().makeSimilarCircle();\n    };\n\n    Polygon.prototype.makeSimilarRectangle = function() {\n        var p,\n            minX = 0,\n            maxX = 0,\n            minY = 0,\n            maxY = 0;\n        for (var i = 0; i < this.points.length; i++) {\n            p = this.points[i];\n            minX = Math.min(minX, p.x);\n            maxX = Math.max(maxX, p.x);\n            minY = Math.min(minY, p.y);\n            maxY = Math.max(maxY, p.y);\n        }\n        return new Rectangle(this.label,\n                this.centre.x + minX, this.centre.y + minY,\n                Math.max(maxX - minX, 10), Math.max(maxY - minY, 10));\n    };\n\n    Polygon.prototype.getHandlePositions = function() {\n        var editHandles = [];\n        for (var i = 0; i < this.points.length; i++) {\n            editHandles.push(this.points[i].offset(this.centre.x, this.centre.y));\n        }\n\n        this.centre.x = this.centre.x * parseFloat(this.ratio);\n        this.centre.y = this.centre.y * parseFloat(this.ratio);\n\n        return {\n            moveHandle: this.centre,\n            editHandles: editHandles\n        };\n    };\n\n\n    /**\n     * Not a shape (null object pattern).\n     *\n     * @param {String} label name of this area.\n     * @constructor\n     */\n    function NullShape(label) {\n        Shape.call(this, label);\n    }\n    NullShape.prototype = new Shape();\n\n    NullShape.prototype.getType = function() {\n        return 'null';\n    };\n\n    NullShape.prototype.getCoordinates = function() {\n        return '';\n    };\n\n    NullShape.prototype.makeSvg = function(svg) {\n        void (svg);\n        return null;\n    };\n\n    NullShape.prototype.updateSvg = function(svgEl) {\n        void (svgEl);\n    };\n\n    NullShape.prototype.parse = function(coordinates) {\n        void (coordinates);\n        return false;\n    };\n\n    NullShape.prototype.makeSimilarCircle = function() {\n        return new Circle(this.label);\n    };\n\n    NullShape.prototype.makeSimilarRectangle = function() {\n        return new Rectangle(this.label);\n    };\n\n    NullShape.prototype.makeSimilarPolygon = function() {\n        return new Polygon(this.label);\n    };\n\n\n    /**\n     * Make a new SVG DOM element as a child of svg.\n     *\n     * @param {SVGElement} svg the parent node.\n     * @param {String} tagName the tag name.\n     * @return {SVGElement} the newly created node.\n     */\n    function createSvgElement(svg, tagName) {\n        var svgEl = svg.ownerDocument.createElementNS('http://www.w3.org/2000/svg', tagName);\n        svg.appendChild(svgEl);\n        return svgEl;\n    }\n\n    /**\n     * Make a group SVG DOM elements containing a shape of the given type as first child,\n     * and a text label as the second child.\n     *\n     * @param {SVGElement} svg the parent node.\n     * @param {String} tagName the tag name.\n     * @return {SVGElement} the newly created g element.\n     */\n    function createSvgShapeGroup(svg, tagName) {\n        var svgEl = createSvgElement(svg, 'g');\n        createSvgElement(svgEl, tagName).setAttribute('class', 'shape');\n        createSvgElement(svgEl, 'text').setAttribute('class', 'shapeLabel');\n        return svgEl;\n    }\n\n    /**\n     * @alias module:qtype_ddmarker/shapes\n     */\n    return {\n        /**\n         * A point, with x and y coordinates.\n         *\n         * @param {int} x centre X.\n         * @param {int} y centre Y.\n         * @constructor\n         */\n        Point: Point,\n\n        /**\n         * A point, with x and y coordinates.\n         *\n         * @param {int} x centre X.\n         * @param {int} y centre Y.\n         * @constructor\n         */\n        Shape: Shape,\n\n        /**\n         * A shape that is a circle.\n         *\n         * @param {String} label name of this area.\n         * @param {int} [x] centre X.\n         * @param {int} [y] centre Y.\n         * @param {int} [radius] radius.\n         * @constructor\n         */\n        Circle: Circle,\n\n        /**\n         * A shape that is a rectangle.\n         *\n         * @param {String} label name of this area.\n         * @param {int} [x] top left X.\n         * @param {int} [y] top left Y.\n         * @param {int} [width] width.\n         * @param {int} [height] height.\n         * @constructor\n         */\n        Rectangle: Rectangle,\n\n        /**\n         * A shape that is a polygon.\n         *\n         * @param {String} label name of this area.\n         * @param {Point[]} [points] position of the vertices relative to (centreX, centreY).\n         *      each object in the array should have two\n         * @constructor\n         */\n        Polygon: Polygon,\n\n        /**\n         * Not a shape (null object pattern).\n         *\n         * @param {String} label name of this area.\n         * @constructor\n         */\n        NullShape: NullShape,\n\n        /**\n         * Make a new SVG DOM element as a child of svg.\n         *\n         * @param {SVGElement} svg the parent node.\n         * @param {String} tagName the tag name.\n         * @return {SVGElement} the newly created node.\n         */\n        createSvgElement: createSvgElement,\n\n        /**\n         * Make a shape of the given type.\n         *\n         * @param {String} shapeType\n         * @param {String} label\n         * @return {Shape} the requested shape.\n         */\n        make: function(shapeType, label) {\n            switch (shapeType) {\n                case 'circle':\n                    return new Circle(label);\n                case 'rectangle':\n                    return new Rectangle(label);\n                case 'polygon':\n                    return new Polygon(label);\n                default:\n                    return new NullShape(label);\n            }\n        },\n\n        /**\n         * Make a shape of the given type that is similar to the shape of the original type.\n         *\n         * @param {String} shapeType the new type of shape to make\n         * @param {Shape} shape the shape to copy\n         * @return {Shape} the similar shape of a different type.\n         */\n        getSimilar: function(shapeType, shape) {\n            if (shapeType === shape.getType()) {\n                return shape;\n            }\n            switch (shapeType) {\n                case 'circle':\n                    return shape.makeSimilarCircle();\n                case 'rectangle':\n                    return shape.makeSimilarRectangle();\n                case 'polygon':\n                    return shape.makeSimilarPolygon();\n                default:\n                    return new NullShape(shape.label);\n            }\n        }\n    };\n});\n"],"names":["define","Point","x","y","Shape","label","centre","Circle","radius","call","this","Rectangle","width","height","Polygon","points","slice","normalizeShape","ratio","NullShape","createSvgElement","svg","tagName","svgEl","ownerDocument","createElementNS","appendChild","createSvgShapeGroup","setAttribute","prototype","toString","move","dx","dy","offset","offsetX","offsetY","parse","coordinates","bits","split","length","Error","Math","round","getType","getCoordinates","maxX","maxY","edit","handleIndex","makeSvg","updateSvg","makeSimilarCircle","makeSimilarRectangle","makeSimilarPolygon","getHandlePositions","abs","childNodes","textContent","match","parseFloat","limit","min","moveHandle","editHandles","size","i","replace","push","bbXMin","bbXMax","bbYMin","bbYMax","max","addNewPointAfter","pointIndex","splice","p","minX","minY","make","shapeType","getSimilar","shape"],"mappings":";;;;;;;;;;AA4BAA,gCAAO,oBAWMC,MAAMC,EAAGC,QACTD,EAAIA,OACJC,EAAIA,WA2DJC,MAAMC,MAAOH,EAAGC,QAChBE,MAAQA,WACRC,OAAS,IAAIL,MAAMC,GAAK,EAAGC,GAAK,YAqIhCI,OAAOF,MAAOH,EAAGC,EAAGK,QACzBN,EAAIA,GAAK,GACTC,EAAIA,GAAK,GACTC,MAAMK,KAAKC,KAAML,MAAOH,EAAGC,QACtBK,OAASA,QAAU,YA2GnBG,UAAUN,MAAOH,EAAGC,EAAGS,MAAOC,QACnCT,MAAMK,KAAKC,KAAML,MAAOH,EAAGC,QACtBS,MAAQA,OAAS,QACjBC,OAASA,QAAU,YAoInBC,QAAQT,MAAOU,QACpBX,MAAMK,KAAKC,KAAML,MAAO,EAAG,QACtBU,OAASA,OAASA,OAAOC,QAAU,CAAC,IAAIf,MAAM,GAAI,IAAK,IAAIA,MAAM,GAAI,IAAK,IAAIA,MAAM,GAAI,UACxFgB,sBACAC,MAAQ,WAgLRC,UAAUd,OACfD,MAAMK,KAAKC,KAAML,gBA8CZe,iBAAiBC,IAAKC,aACvBC,MAAQF,IAAIG,cAAcC,gBAAgB,6BAA8BH,gBAC5ED,IAAIK,YAAYH,OACTA,eAWFI,oBAAoBN,IAAKC,aAC1BC,MAAQH,iBAAiBC,IAAK,YAClCD,iBAAiBG,MAAOD,SAASM,aAAa,QAAS,SACvDR,iBAAiBG,MAAO,QAAQK,aAAa,QAAS,cAC/CL,aAtqBXtB,MAAM4B,UAAUC,SAAW,kBAChBpB,KAAKR,EAAI,IAAMQ,KAAKP,GAQ/BF,MAAM4B,UAAUE,KAAO,SAASC,GAAIC,SAC3B/B,GAAK8B,QACL7B,GAAK8B,IAUdhC,MAAM4B,UAAUK,OAAS,SAASC,QAASC,gBACnCD,mBAAmBlC,QACnBmC,QAAUD,QAAQhC,EAClBgC,QAAUA,QAAQjC,GAEf,IAAID,MAAMS,KAAKR,EAAIiC,QAASzB,KAAKP,EAAIiC,UAShDnC,MAAMoC,MAAQ,SAASC,iBACfC,KAAOD,YAAYE,MAAM,QACT,IAAhBD,KAAKE,aACC,IAAIC,MAAMJ,YAAc,gCAE3B,IAAIrC,MAAM0C,KAAKC,MAAML,KAAK,IAAKI,KAAKC,MAAML,KAAK,MAsB1DnC,MAAMyB,UAAUgB,QAAU,iBAChB,IAAIH,MAAM,qBAQpBtC,MAAMyB,UAAUiB,eAAiB,iBACvB,IAAIJ,MAAM,qBAUpBtC,MAAMyB,UAAUQ,MAAQ,SAASC,YAAapB,aAEpC,IAAIwB,MAAM,qBAWpBtC,MAAMyB,UAAUE,KAAO,SAASC,GAAIC,GAAIc,KAAMC,QAa9C5C,MAAMyB,UAAUoB,KAAO,SAASC,YAAalB,GAAIC,GAAIc,KAAMC,QAS3D5C,MAAMyB,UAAUZ,eAAiB,aAUjCb,MAAMyB,UAAUsB,QAAU,SAAS9B,WAEzB,IAAIqB,MAAM,qBAQpBtC,MAAMyB,UAAUuB,UAAY,SAAS7B,SASrCnB,MAAMyB,UAAUwB,kBAAoB,iBAC1B,IAAIX,MAAM,qBAQpBtC,MAAMyB,UAAUyB,qBAAuB,iBAC7B,IAAIZ,MAAM,qBAQpBtC,MAAMyB,UAAU0B,mBAAqB,iBAC3B,IAAIb,MAAM,qBAQpBtC,MAAMyB,UAAU2B,mBAAqB,kBAC1B,MAmBXjD,OAAOsB,UAAY,IAAIzB,MAEvBG,OAAOsB,UAAUgB,QAAU,iBAChB,UAGXtC,OAAOsB,UAAUiB,eAAiB,kBACvBpC,KAAKJ,OAAS,IAAMqC,KAAKc,IAAI/C,KAAKF,SAG7CD,OAAOsB,UAAUsB,QAAU,SAAS9B,SAC5BE,MAAQI,oBAAoBN,IAAK,sBAChC+B,UAAU7B,OACRA,OAGXhB,OAAOsB,UAAUuB,UAAY,SAAS7B,OAClCA,MAAMmC,WAAW,GAAG9B,aAAa,KAAMlB,KAAKJ,OAAOJ,GACnDqB,MAAMmC,WAAW,GAAG9B,aAAa,KAAMlB,KAAKJ,OAAOH,GACnDoB,MAAMmC,WAAW,GAAG9B,aAAa,IAAKe,KAAKc,IAAI/C,KAAKF,SACpDe,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOJ,GAClDqB,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOH,EAAI,IACtDoB,MAAMmC,WAAW,GAAGC,YAAcjD,KAAKL,OAG3CE,OAAOsB,UAAUQ,MAAQ,SAASC,YAAapB,WACtCoB,YAAYsB,MAAM,gDACZ,MAGPrB,KAAOD,YAAYE,MAAM,iBACxBlC,OAASL,MAAMoC,MAAME,KAAK,SAC1BjC,OAAOJ,EAAIQ,KAAKJ,OAAOJ,EAAI2D,WAAW3C,YACtCZ,OAAOH,EAAIO,KAAKJ,OAAOH,EAAI0D,WAAW3C,YACtCV,OAASmC,KAAKC,MAAML,KAAK,IAAMsB,WAAW3C,QACxC,GAGXX,OAAOsB,UAAUE,KAAO,SAASC,GAAIC,GAAIc,KAAMC,WACtC1C,OAAOyB,KAAKC,GAAIC,IACjBvB,KAAKJ,OAAOJ,EAAIQ,KAAKF,cAChBF,OAAOJ,EAAIQ,KAAKF,QAErBE,KAAKJ,OAAOJ,EAAI6C,KAAOrC,KAAKF,cACvBF,OAAOJ,EAAI6C,KAAOrC,KAAKF,QAE5BE,KAAKJ,OAAOH,EAAIO,KAAKF,cAChBF,OAAOH,EAAIO,KAAKF,QAErBE,KAAKJ,OAAOH,EAAI6C,KAAOtC,KAAKF,cACvBF,OAAOH,EAAI6C,KAAOtC,KAAKF,SAIpCD,OAAOsB,UAAUoB,KAAO,SAASC,YAAalB,GAAIC,GAAIc,KAAMC,WACnDxC,QAAUwB,OACX8B,MAAQnB,KAAKoB,IAAIrD,KAAKJ,OAAOJ,EAAGQ,KAAKJ,OAAOH,EAAG4C,KAAOrC,KAAKJ,OAAOJ,EAAG8C,KAAOtC,KAAKJ,OAAOH,GACxFO,KAAKF,OAASsD,aACTtD,OAASsD,OAEdpD,KAAKF,QAAUsD,aACVtD,QAAUsD,QASvBvD,OAAOsB,UAAUZ,eAAiB,gBACzBT,OAASmC,KAAKc,IAAI/C,KAAKF,SAGhCD,OAAOsB,UAAUyB,qBAAuB,kBAC7B,IAAI3C,UAAUD,KAAKL,MAClBK,KAAKJ,OAAOJ,EAAIQ,KAAKF,OAAQE,KAAKJ,OAAOH,EAAIO,KAAKF,OACpC,EAAdE,KAAKF,OAA0B,EAAdE,KAAKF,SAGlCD,OAAOsB,UAAU0B,mBAAqB,kBAE3B,IAAIzC,QAAQJ,KAAKL,MAAO,CACvBK,KAAKJ,OAAO4B,QAAQxB,KAAKF,QAASE,KAAKF,QAASE,KAAKJ,OAAO4B,QAAQxB,KAAKF,OAAQE,KAAKF,QACtFE,KAAKJ,OAAO4B,OAAOxB,KAAKF,OAAQE,KAAKF,QAASE,KAAKJ,OAAO4B,OAAOxB,KAAKF,QAASE,KAAKF,WAGhGD,OAAOsB,UAAU2B,mBAAqB,iBAC3B,CACHQ,WAAYtD,KAAKJ,OACjB2D,YAAa,CAACvD,KAAKJ,OAAO4B,OAAOxB,KAAKF,OAAQ,MAoBtDG,UAAUkB,UAAY,IAAIzB,MAE1BO,UAAUkB,UAAUgB,QAAU,iBACnB,aAGXlC,UAAUkB,UAAUiB,eAAiB,kBAC1BpC,KAAKJ,OAAS,IAAMI,KAAKE,MAAQ,IAAMF,KAAKG,QAGvDF,UAAUkB,UAAUsB,QAAU,SAAS9B,SAC/BE,MAAQI,oBAAoBN,IAAK,oBAChC+B,UAAU7B,OACRA,OAGXZ,UAAUkB,UAAUuB,UAAY,SAAS7B,OACjCb,KAAKE,OAAS,GACdW,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOJ,GAClDqB,MAAMmC,WAAW,GAAG9B,aAAa,QAASlB,KAAKE,SAE/CW,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOJ,EAAIQ,KAAKE,OAC3DW,MAAMmC,WAAW,GAAG9B,aAAa,SAAUlB,KAAKE,QAEhDF,KAAKG,QAAU,GACfU,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOH,GAClDoB,MAAMmC,WAAW,GAAG9B,aAAa,SAAUlB,KAAKG,UAEhDU,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOH,EAAIO,KAAKG,QAC3DU,MAAMmC,WAAW,GAAG9B,aAAa,UAAWlB,KAAKG,SAGrDU,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOJ,EAAIQ,KAAKE,MAAQ,GACnEW,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOH,EAAIO,KAAKG,OAAS,EAAI,IACxEU,MAAMmC,WAAW,GAAGC,YAAcjD,KAAKL,OAG3CM,UAAUkB,UAAUQ,MAAQ,SAASC,YAAapB,WACzCoB,YAAYsB,MAAM,4DACZ,MAGPrB,KAAOD,YAAYE,MAAM,UACxBlC,OAASL,MAAMoC,MAAME,KAAK,SAC1BjC,OAAOJ,EAAIQ,KAAKJ,OAAOJ,EAAI2D,WAAW3C,YACtCZ,OAAOH,EAAIO,KAAKJ,OAAOH,EAAI0D,WAAW3C,WACvCgD,KAAOjE,MAAMoC,MAAME,KAAK,gBACvB3B,MAAQsD,KAAKhE,EAAI2D,WAAW3C,YAC5BL,OAASqD,KAAK/D,EAAI0D,WAAW3C,QAC3B,GAGXP,UAAUkB,UAAUE,KAAO,SAASC,GAAIC,GAAIc,KAAMC,WACzC1C,OAAOyB,KAAKC,GAAIC,IACjBvB,KAAKJ,OAAOJ,EAAI,SACXI,OAAOJ,EAAI,GAEhBQ,KAAKJ,OAAOJ,EAAI6C,KAAOrC,KAAKE,aACvBN,OAAOJ,EAAI6C,KAAOrC,KAAKE,OAE5BF,KAAKJ,OAAOH,EAAI,SACXG,OAAOH,EAAI,GAEhBO,KAAKJ,OAAOH,EAAI6C,KAAOtC,KAAKG,cACvBP,OAAOH,EAAI6C,KAAOtC,KAAKG,SAIpCF,UAAUkB,UAAUoB,KAAO,SAASC,YAAalB,GAAIC,GAAIc,KAAMC,WACtDpC,OAASoB,QACTnB,QAAUoB,GACXvB,KAAKE,OAASF,KAAKJ,OAAOJ,SACrBU,OAASF,KAAKJ,OAAOJ,GAE1BQ,KAAKE,MAAQmC,KAAOrC,KAAKJ,OAAOJ,SAC3BU,MAAQmC,KAAOrC,KAAKJ,OAAOJ,GAEhCQ,KAAKG,QAAUH,KAAKJ,OAAOH,SACtBU,QAAUH,KAAKJ,OAAOH,GAE3BO,KAAKG,OAASmC,KAAOtC,KAAKJ,OAAOH,SAC5BU,OAASmC,KAAOtC,KAAKJ,OAAOH,IASzCQ,UAAUkB,UAAUZ,eAAiB,WAC7BP,KAAKE,MAAQ,SACRN,OAAOJ,GAAKQ,KAAKE,WACjBA,OAASF,KAAKE,OAEnBF,KAAKG,OAAS,SACTP,OAAOH,GAAKO,KAAKG,YACjBA,QAAUH,KAAKG,SAI5BF,UAAUkB,UAAUwB,kBAAoB,kBAC7B,IAAI9C,OAAOG,KAAKL,MACfsC,KAAKC,MAAMlC,KAAKJ,OAAOJ,EAAIQ,KAAKE,MAAQ,GACxC+B,KAAKC,MAAMlC,KAAKJ,OAAOH,EAAIO,KAAKG,OAAS,GACzC8B,KAAKC,OAAOlC,KAAKE,MAAQF,KAAKG,QAAU,KAGpDF,UAAUkB,UAAU0B,mBAAqB,kBAC9B,IAAIzC,QAAQJ,KAAKL,MAAO,CAC3BK,KAAKJ,OAAQI,KAAKJ,OAAO4B,OAAO,EAAGxB,KAAKG,QACxCH,KAAKJ,OAAO4B,OAAOxB,KAAKE,MAAOF,KAAKG,QAASH,KAAKJ,OAAO4B,OAAOxB,KAAKE,MAAO,MAGpFD,UAAUkB,UAAU2B,mBAAqB,iBAC9B,CACHQ,WAAYtD,KAAKJ,OAAO4B,OAAOxB,KAAKE,MAAQ,EAAGF,KAAKG,OAAS,GAC7DoD,YAAa,CAACvD,KAAKJ,OAAO4B,OAAOxB,KAAKE,MAAOF,KAAKG,WAmB1DC,QAAQe,UAAY,IAAIzB,MAExBU,QAAQe,UAAUgB,QAAU,iBACjB,WAGX/B,QAAQe,UAAUiB,eAAiB,mBAC3BR,YAAc,GACT6B,EAAI,EAAGA,EAAIzD,KAAKK,OAAO0B,OAAQ0B,IACpC7B,aAAe5B,KAAKJ,OAAO4B,OAAOxB,KAAKK,OAAOoD,IAAM,WAEjD7B,YAAYtB,MAAM,EAAGsB,YAAYG,OAAS,IAGrD3B,QAAQe,UAAUsB,QAAU,SAAS9B,SAC7BE,MAAQI,oBAAoBN,IAAK,uBAChC+B,UAAU7B,OACRA,OAGXT,QAAQe,UAAUuB,UAAY,SAAS7B,OACnCA,MAAMmC,WAAW,GAAG9B,aAAa,SAAUlB,KAAKoC,iBAAiBsB,QAAQ,QAAS,MAClF7C,MAAMmC,WAAW,GAAG9B,aAAa,YAAa,SAAWiC,WAAWnD,KAAKQ,OAAS,KAClFK,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOJ,GAClDqB,MAAMmC,WAAW,GAAG9B,aAAa,IAAKlB,KAAKJ,OAAOH,EAAI,IACtDoB,MAAMmC,WAAW,GAAGC,YAAcjD,KAAKL,OAG3CS,QAAQe,UAAUQ,MAAQ,SAASC,YAAapB,WACvCoB,YAAYsB,MAAM,iEACZ,UAGPrB,KAAOD,YAAYE,MAAM,KACzBzB,OAAS,GACJoD,EAAI,EAAGA,EAAI5B,KAAKE,OAAQ0B,IAC7BpD,OAAOsD,KAAKpE,MAAMoC,MAAME,KAAK4B,iBAG5BpD,OAASA,YACTT,OAAOJ,EAAI,OACXI,OAAOH,EAAI,OACXe,MAAQA,WACRD,kBAEE,GAGXH,QAAQe,UAAUE,KAAO,SAASC,GAAIC,GAAIc,KAAMC,WACvC1C,OAAOyB,KAAKC,GAAIC,YACjBqC,OAASvB,KACTwB,OAAS,EACTC,OAASxB,KACTyB,OAAS,EAEJN,EAAI,EAAGA,EAAIzD,KAAKK,OAAO0B,OAAQ0B,IACpCG,OAAS3B,KAAKoB,IAAIO,OAAQ5D,KAAKK,OAAOoD,GAAGjE,GACzCqE,OAAS5B,KAAK+B,IAAIH,OAAQ7D,KAAKK,OAAOoD,GAAGjE,GACzCsE,OAAS7B,KAAKoB,IAAIS,OAAQ9D,KAAKK,OAAOoD,GAAGhE,GACzCsE,OAAS9B,KAAK+B,IAAID,OAAQ/D,KAAKK,OAAOoD,GAAGhE,GAEzCO,KAAKJ,OAAOJ,GAAKoE,cACZhE,OAAOJ,GAAKoE,QAEjB5D,KAAKJ,OAAOJ,EAAI6C,KAAOwB,cAClBjE,OAAOJ,EAAI6C,KAAOwB,QAEvB7D,KAAKJ,OAAOH,GAAKqE,cACZlE,OAAOH,GAAKqE,QAEjB9D,KAAKJ,OAAOH,EAAI6C,KAAOyB,cAClBnE,OAAOH,EAAI6C,KAAOyB,SAI/B3D,QAAQe,UAAUoB,KAAO,SAASC,YAAalB,GAAIC,GAAIc,KAAMC,WACpDjC,OAAOmC,aAAanB,KAAKC,GAAIC,IAC9BvB,KAAKK,OAAOmC,aAAahD,GAAKQ,KAAKJ,OAAOJ,SACrCa,OAAOmC,aAAahD,GAAKQ,KAAKJ,OAAOJ,GAE1CQ,KAAKK,OAAOmC,aAAahD,EAAI6C,KAAOrC,KAAKJ,OAAOJ,SAC3Ca,OAAOmC,aAAahD,EAAI6C,KAAOrC,KAAKJ,OAAOJ,GAEhDQ,KAAKK,OAAOmC,aAAa/C,GAAKO,KAAKJ,OAAOH,SACrCY,OAAOmC,aAAa/C,GAAKO,KAAKJ,OAAOH,GAE1CO,KAAKK,OAAOmC,aAAa/C,EAAI6C,KAAOtC,KAAKJ,OAAOH,SAC3CY,OAAOmC,aAAa/C,EAAI6C,KAAOtC,KAAKJ,OAAOH,IAWxDW,QAAQe,UAAU8C,iBAAmB,SAASC,iBACrC7D,OAAO8D,OAAOD,WAAY,EACvB,IAAI3E,MAAMS,KAAKK,OAAO6D,YAAY1E,EAAGQ,KAAKK,OAAO6D,YAAYzE,KAGzEW,QAAQe,UAAUZ,eAAiB,eAC3BkD,EACAjE,EAAI,EACJC,EAAI,KAEmB,IAAvBO,KAAKK,OAAO0B,YAKX0B,EAAI,EAAGA,EAAIzD,KAAKK,OAAO0B,OAAQ0B,IAChCjE,GAAKQ,KAAKK,OAAOoD,GAAGjE,EACpBC,GAAKO,KAAKK,OAAOoD,GAAGhE,KAExBD,EAAIyC,KAAKC,MAAM1C,EAAIQ,KAAKK,OAAO0B,QAC/BtC,EAAIwC,KAAKC,MAAMzC,EAAIO,KAAKK,OAAO0B,QAErB,IAANvC,GAAiB,IAANC,OAIVgE,EAAI,EAAGA,EAAIzD,KAAKK,OAAO0B,OAAQ0B,SAC3BpD,OAAOoD,GAAGpC,MAAM7B,GAAIC,QAExBG,OAAOyB,KAAK7B,EAAGC,MAGxBW,QAAQe,UAAUwB,kBAAoB,kBAC3B3C,KAAK4C,uBAAuBD,qBAGvCvC,QAAQe,UAAUyB,qBAAuB,mBACjCwB,EACAC,KAAO,EACPhC,KAAO,EACPiC,KAAO,EACPhC,KAAO,EACFmB,EAAI,EAAGA,EAAIzD,KAAKK,OAAO0B,OAAQ0B,IACpCW,EAAIpE,KAAKK,OAAOoD,GAChBY,KAAOpC,KAAKoB,IAAIgB,KAAMD,EAAE5E,GACxB6C,KAAOJ,KAAK+B,IAAI3B,KAAM+B,EAAE5E,GACxB8E,KAAOrC,KAAKoB,IAAIiB,KAAMF,EAAE3E,GACxB6C,KAAOL,KAAK+B,IAAI1B,KAAM8B,EAAE3E,UAErB,IAAIQ,UAAUD,KAAKL,MAClBK,KAAKJ,OAAOJ,EAAI6E,KAAMrE,KAAKJ,OAAOH,EAAI6E,KACtCrC,KAAK+B,IAAI3B,KAAOgC,KAAM,IAAKpC,KAAK+B,IAAI1B,KAAOgC,KAAM,MAG7DlE,QAAQe,UAAU2B,mBAAqB,mBAC/BS,YAAc,GACTE,EAAI,EAAGA,EAAIzD,KAAKK,OAAO0B,OAAQ0B,IACpCF,YAAYI,KAAK3D,KAAKK,OAAOoD,GAAGjC,OAAOxB,KAAKJ,OAAOJ,EAAGQ,KAAKJ,OAAOH,gBAGjEG,OAAOJ,EAAIQ,KAAKJ,OAAOJ,EAAI2D,WAAWnD,KAAKQ,YAC3CZ,OAAOH,EAAIO,KAAKJ,OAAOH,EAAI0D,WAAWnD,KAAKQ,OAEzC,CACH8C,WAAYtD,KAAKJ,OACjB2D,YAAaA,cAcrB9C,UAAUU,UAAY,IAAIzB,MAE1Be,UAAUU,UAAUgB,QAAU,iBACnB,QAGX1B,UAAUU,UAAUiB,eAAiB,iBAC1B,IAGX3B,UAAUU,UAAUsB,QAAU,SAAS9B,YAE5B,MAGXF,UAAUU,UAAUuB,UAAY,SAAS7B,SAIzCJ,UAAUU,UAAUQ,MAAQ,SAASC,oBAE1B,GAGXnB,UAAUU,UAAUwB,kBAAoB,kBAC7B,IAAI9C,OAAOG,KAAKL,QAG3Bc,UAAUU,UAAUyB,qBAAuB,kBAChC,IAAI3C,UAAUD,KAAKL,QAG9Bc,UAAUU,UAAU0B,mBAAqB,kBAC9B,IAAIzC,QAAQJ,KAAKL,QAmCrB,CAQHJ,MAAOA,MASPG,MAAOA,MAWPG,OAAQA,OAYRI,UAAWA,UAUXG,QAASA,QAQTK,UAAWA,UASXC,iBAAkBA,iBASlB6D,KAAM,SAASC,UAAW7E,cACd6E,eACC,gBACM,IAAI3E,OAAOF,WACjB,mBACM,IAAIM,UAAUN,WACpB,iBACM,IAAIS,QAAQT,sBAEZ,IAAIc,UAAUd,SAWjC8E,WAAY,SAASD,UAAWE,UACxBF,YAAcE,MAAMvC,iBACbuC,aAEHF,eACC,gBACME,MAAM/B,wBACZ,mBACM+B,MAAM9B,2BACZ,iBACM8B,MAAM7B,oCAEN,IAAIpC,UAAUiE,MAAM/E"}