{"version":3,"file":"app-7f781c8c.f584a1446b2fc034d810.bundle.js","mappings":"AACA","sources":["webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/msvg/msvg.js","webpack://lernplattform-admin-frontend/../common/aurelia-components/css-bar-chart-bar/css-bar-chart-bar.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/css-bar-chart/css-bar-chart.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/custom-select-answer-overlay/custom-select-answer-overlay.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-conference-student-view/distinar-conference-student-view.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-course-picture-overlay/distinar-course-picture-overlay.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-floating-video-container/distinar-floating-video-container.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-whiteboard-viewer/distinar-whiteboard-viewer.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/donut-chart/donut-chart.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/drawing-area.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/dropdown-select/dropdown-select-label.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/dropdown-select/dropdown-select.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/css-bar-chart-bar/css-bar-chart-bar.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/css-bar-chart-bar/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/css-bar-chart/css-bar-chart.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/css-bar-chart/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/custom-select-answer-overlay/custom-select-answer-overlay.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/custom-select-answer-overlay/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-conference-student-view/distinar-conference-student-view.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-conference-student-view/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-course-picture-overlay/distinar-course-picture-overlay.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-course-picture-overlay/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-floating-video-container/distinar-floating-video-container.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-floating-video-container/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-whiteboard-viewer/distinar-whiteboard-viewer.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/distinar-whiteboard-viewer/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/donut-chart/donut-chart.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/donut-chart/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/drawing-area.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/ArrowTool.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/DeleteTool.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/EllipseTool.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/FreehandTool.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/LineTool.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/RectangleTool.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/SvgPointerEventNormalizer.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/Tool.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/ToolEventDelegator.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/tools/ToolGrid.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/DelayedQueue.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/DomEventHelper.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/DrawingHistoryManager.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/EventDispatcher.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/Geometry/AngleHelper.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/Geometry/TransformHelper.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/Geometry/Vector.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/ImageHelper.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/PointerEventHelper.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/Svg/SvgCleaner.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/drawing-area/util/Utils.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/dropdown-select/dropdown-select-label.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/dropdown-select/dropdown-select.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/dropdown-select/index.ts"],"sourcesContent":["/* eslint-disable */\nvar __extends = (this && this.__extends) || (function () {\n    var extendStatics = Object.setPrototypeOf ||\n        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n    return function (d, b) {\n        extendStatics(d, b);\n        function __() { this.constructor = d; }\n        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n    };\n})();\nvar Msvg;\n(function (Msvg) {\n    /**\n     * base class for general MsvgElements\n     */\n    var MsvgElement = /** @class */ (function () {\n        function MsvgElement(element) {\n            this.children = [];\n            this.element = element ? element : MsvgElement.createSvgElement(this.constructor.tagname);\n        }\n        MsvgElement.prototype.getElement = function () {\n            return this.element;\n        };\n        MsvgElement.prototype.append = function (child) {\n            this.element.appendChild(child.getElement());\n            this.children.push(child);\n            return this;\n        };\n        MsvgElement.prototype.remove = function (child) {\n            this.element.removeChild(child.getElement());\n            var index = this.children.indexOf(child);\n            if (index >= 0) {\n                this.children.splice(index, 1);\n            }\n            return this;\n        };\n        /**\n         * use this function if you only have the reference to the svgElement itself, and not the msvgElement\n         * @param child\n         */\n        MsvgElement.prototype.removeSvgElement = function (child) {\n            this.element.removeChild(child);\n            for (var key = this.children.length - 1; key >= 0; key--) {\n                var c = this.children[key];\n                if (c.getElement() === child) {\n                    this.children.splice(key, 1);\n                }\n            }\n            return this;\n        };\n        MsvgElement.prototype.empty = function () {\n            while (this.element.firstChild) {\n                this.element.removeChild(this.element.firstChild);\n            }\n            this.children.length = 0;\n        };\n        MsvgElement.prototype.getChildren = function () {\n            return this.children.slice(0); //return a shallow copy\n        };\n        MsvgElement.prototype.setAttribute = function (name, value) {\n            if (value != null) {\n                var stringValue = (value != null ? value.toString() : value);\n                this.element.setAttribute(name, stringValue);\n            }\n            else {\n                this.element.removeAttribute(name);\n            }\n            return this;\n        };\n        MsvgElement.prototype.getAttribute = function (name) {\n            return this.element.getAttribute(name);\n        };\n        /**\n         * string has to be in this style: '<element-tagname>childs or whatever</element-tagname>'\n         *\n         * @param svgString\n         */\n        MsvgElement.createFromString = function (svgString) {\n            var msvg = new Msvg.Msvg();\n            var svgElement = msvg.getElement();\n            svgElement.innerHTML = svgString;\n            var element = new MsvgElement();\n            element.element = svgElement.firstElementChild;\n            return element;\n        };\n        MsvgElement.createSvgElement = function (tagName) {\n            return document.createElementNS(Msvg.Utils.Definitions.svgNamespace, tagName);\n        };\n        /**\n         * has to be implemented by the extending constructor\n         */\n        MsvgElement.tagname = 'msvg-element';\n        return MsvgElement;\n    }());\n    Msvg.MsvgElement = MsvgElement;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    /**\n     * provides a class for svg elements which have a stroke/fill\n     */\n    var MsvgDrawingElement = /** @class */ (function (_super) {\n        __extends(MsvgDrawingElement, _super);\n        function MsvgDrawingElement() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * stroke color, e.g. red, rgb(111,111,111), #beef00\n         */\n        MsvgDrawingElement.prototype.setStroke = function (stroke) {\n            return this.setAttribute('stroke', stroke);\n        };\n        MsvgDrawingElement.prototype.getStroke = function () {\n            return this.getAttribute('stroke');\n        };\n        /**\n         * width of the stroke, unitless\n         * the stroke gets centered on the ideal line\n         */\n        MsvgDrawingElement.prototype.setStrokeWidth = function (width) {\n            return this.setAttribute('stroke-width', width);\n        };\n        MsvgDrawingElement.prototype.getStrokeWidth = function () {\n            return this.getAttribute('stroke-width');\n        };\n        /**\n         * opacity of the stroke\n         */\n        MsvgDrawingElement.prototype.setStrokeOpacity = function (opacity) {\n            return this.setAttribute('stroke-opacity', opacity);\n        };\n        MsvgDrawingElement.prototype.getStrokeOpacity = function () {\n            return this.getAttribute('stroke-opacity');\n        };\n        /**\n         * style of the linejoin\n         */\n        MsvgDrawingElement.prototype.setStrokeLinejoin = function (linejoin) {\n            return this.setAttribute('stroke-linejoin', linejoin);\n        };\n        MsvgDrawingElement.prototype.getStrokeLinejoin = function () {\n            return this.getAttribute('stroke-linejoin');\n        };\n        /**\n         * fill color, e.g. red, rgb(111,111,111), #beef00\n         */\n        MsvgDrawingElement.prototype.setFill = function (fill) {\n            return this.setAttribute('fill', fill);\n        };\n        MsvgDrawingElement.prototype.getFill = function () {\n            return this.getAttribute('fill');\n        };\n        /**\n         * opacity of the fill color, e.g. 0.1, 1, 0\n         */\n        MsvgDrawingElement.prototype.setFillOpacity = function (opacity) {\n            return this.setAttribute('fill-opacity', opacity);\n        };\n        MsvgDrawingElement.prototype.getFillOpacity = function () {\n            return this.getAttribute('fill-opacity');\n        };\n        /**\n         * fill rule of the element, e.g. nonzero, evenodd...\n         */\n        MsvgDrawingElement.prototype.setFillRule = function (fillRule) {\n            return this.setAttribute('fill-rule', fillRule);\n        };\n        MsvgDrawingElement.prototype.getFillRule = function () {\n            return this.getAttribute('fill-rule');\n        };\n        /**\n         * opacity of the whole element, including fill and stroke\n         */\n        MsvgDrawingElement.prototype.setOpacity = function (opacity) {\n            return this.setAttribute('opacity', opacity);\n        };\n        MsvgDrawingElement.prototype.getOpacity = function () {\n            return this.getAttribute('opacity');\n        };\n        /**\n         * ([sdfat] are optional)\n         * examples:\n         * rotate(rotation [rotationCenterX] [rotationCenterY])\n         */\n        MsvgDrawingElement.prototype.setTransform = function (transform) {\n            return this.setAttribute('transform', transform);\n        };\n        MsvgDrawingElement.prototype.getTransform = function () {\n            return this.getAttribute('transform');\n        };\n        return MsvgDrawingElement;\n    }(Msvg.MsvgElement));\n    Msvg.MsvgDrawingElement = MsvgDrawingElement;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgDrawingElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Circle = /** @class */ (function (_super) {\n        __extends(Circle, _super);\n        function Circle() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * center point of the circle\n         */\n        Circle.prototype.setCenterPosition = function (center) {\n            this.setCx(center.x);\n            return this.setCy(center.y);\n        };\n        Circle.prototype.getCenterPosition = function () {\n            var cx = this.getCx();\n            var cy = this.getCy();\n            return new Msvg.Point(cx ? parseFloat(cx) : null, cy ? parseFloat(cy) : null);\n        };\n        /**\n         * center point x coordinate\n         */\n        Circle.prototype.setCx = function (x) {\n            return this.setAttribute('cx', x);\n        };\n        Circle.prototype.getCx = function () {\n            return this.getAttribute('cx');\n        };\n        /**\n         * center point y coordinate\n         */\n        Circle.prototype.setCy = function (y) {\n            return this.setAttribute('cy', y);\n        };\n        Circle.prototype.getCy = function () {\n            return this.getAttribute('cy');\n        };\n        /**\n         * radius of the circle\n         */\n        Circle.prototype.setR = function (radius) {\n            return this.setAttribute('r', radius);\n        };\n        Circle.prototype.getR = function () {\n            return this.getAttribute('r');\n        };\n        Circle.tagname = 'circle';\n        return Circle;\n    }(Msvg.MsvgDrawingElement));\n    Msvg.Circle = Circle;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Defs = /** @class */ (function (_super) {\n        __extends(Defs, _super);\n        function Defs() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * creates a defs element from a string\n         * the string should only contain the content of the defs element\n         */\n        Defs.createFromString = function (svgString) {\n            var defs = new Defs();\n            defs.getElement().innerHTML = svgString;\n            return defs;\n        };\n        Defs.tagname = 'defs';\n        return Defs;\n    }(Msvg.MsvgElement));\n    Msvg.Defs = Defs;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgDrawingElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Ellipse = /** @class */ (function (_super) {\n        __extends(Ellipse, _super);\n        function Ellipse() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * center point of the circle\n         */\n        Ellipse.prototype.setCenterPosition = function (center) {\n            this.setCx(center.x);\n            return this.setCy(center.y);\n        };\n        Ellipse.prototype.getCenterPosition = function () {\n            var cx = this.getCx();\n            var cy = this.getCy();\n            return new Msvg.Point(cx ? parseFloat(cx) : null, cy ? parseFloat(cy) : null);\n        };\n        /**\n         * center point x coordinate\n         */\n        Ellipse.prototype.setCx = function (x) {\n            return this.setAttribute('cx', x);\n        };\n        Ellipse.prototype.getCx = function () {\n            return this.getAttribute('cx');\n        };\n        /**\n         * center point y coordinate\n         */\n        Ellipse.prototype.setCy = function (y) {\n            return this.setAttribute('cy', y);\n        };\n        Ellipse.prototype.getCy = function () {\n            return this.getAttribute('cy');\n        };\n        /**\n         * x radius of the ellipse\n         */\n        Ellipse.prototype.setRx = function (rx) {\n            return this.setAttribute('rx', rx);\n        };\n        Ellipse.prototype.getRx = function () {\n            return this.getAttribute('rx');\n        };\n        /**\n         * y radius of the ellipse\n         */\n        Ellipse.prototype.setRy = function (ry) {\n            return this.setAttribute('ry', ry);\n        };\n        Ellipse.prototype.getRy = function () {\n            return this.getAttribute('ry');\n        };\n        Ellipse.tagname = 'ellipse';\n        return Ellipse;\n    }(Msvg.MsvgDrawingElement));\n    Msvg.Ellipse = Ellipse;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgDrawingElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Group = /** @class */ (function (_super) {\n        __extends(Group, _super);\n        function Group() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * creates a group element from a string\n         * string may or may not contain the svg tag\n         */\n        Group.createFromString = function (svgString) {\n            var group = new Group();\n            var groupElement = group.getElement();\n            var element = Msvg.Msvg.getSvgElementFromString(svgString);\n            while (element.firstChild) {\n                groupElement.appendChild(element.firstChild);\n            }\n            return group;\n        };\n        Group.tagname = 'g';\n        return Group;\n    }(Msvg.MsvgDrawingElement));\n    Msvg.Group = Group;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgDrawingElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Line = /** @class */ (function (_super) {\n        __extends(Line, _super);\n        function Line() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * set the \"start position\"\n         */\n        Line.prototype.setPosition1 = function (position) {\n            this.setX1(position.x);\n            return this.setY1(position.y);\n        };\n        Line.prototype.getPosition1 = function () {\n            var x = this.getX1();\n            var y = this.getY1();\n            return new Msvg.Point(x != null ? parseFloat(x) : null, y != null ? parseFloat(y) : null);\n        };\n        /**\n         * set the \"end position\"\n         */\n        Line.prototype.setPosition2 = function (position) {\n            this.setX2(position.x);\n            return this.setY2(position.y);\n        };\n        Line.prototype.getPosition2 = function () {\n            var x = this.getX2();\n            var y = this.getY2();\n            return new Msvg.Point(x != null ? parseFloat(x) : null, y != null ? parseFloat(y) : null);\n        };\n        /**\n         * x coordinate of \"start position\"\n         */\n        Line.prototype.setX1 = function (x1) {\n            return this.setAttribute('x1', x1);\n        };\n        Line.prototype.getX1 = function () {\n            return this.getAttribute('x1');\n        };\n        /**\n         * y coordinate of \"start position\"\n         */\n        Line.prototype.setY1 = function (y1) {\n            return this.setAttribute('y1', y1);\n        };\n        Line.prototype.getY1 = function () {\n            return this.getAttribute('y1');\n        };\n        /**\n         * x coordinate of \"end position\"\n         */\n        Line.prototype.setX2 = function (x2) {\n            return this.setAttribute('x2', x2);\n        };\n        Line.prototype.getX2 = function () {\n            return this.getAttribute('x2');\n        };\n        /**\n         * y coordinate of \"end position\"\n         */\n        Line.prototype.setY2 = function (y2) {\n            return this.setAttribute('y2', y2);\n        };\n        Line.prototype.getY2 = function () {\n            return this.getAttribute('y2');\n        };\n        Line.tagname = 'line';\n        return Line;\n    }(Msvg.MsvgDrawingElement));\n    Msvg.Line = Line;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgElement.ts\" />\n//TODO: make a class which has some values as constant (values as in line-caps, fill-rules...)\nvar Msvg;\n(function (Msvg_1) {\n    var Msvg = /** @class */ (function (_super) {\n        __extends(Msvg, _super);\n        function Msvg() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * '0 0 100 100' is a good value for quadratic drawings\n         */\n        Msvg.prototype.setViewBox = function (value) {\n            return this.setAttribute('viewBox', value);\n        };\n        Msvg.prototype.setViewBoxWithPoints = function (p1, p2) {\n            return this.setAttribute('viewBox', p1.toString() + ' ' + p2.toString());\n        };\n        Msvg.prototype.getViewBox = function () {\n            return this.element.viewBox.baseVal;\n        };\n        Msvg.prototype.getElement = function () {\n            return _super.prototype.getElement.call(this);\n        };\n        Msvg.getSvgElementFromString = function (svgString) {\n            if (svgString.indexOf('<svg') == 0) {\n                var div = document.createElement('div');\n                div.innerHTML = svgString;\n                return div.childNodes[0];\n            }\n            else {\n                var svgElement = new Msvg().getElement();\n                svgElement.innerHTML = svgString;\n                return svgElement;\n            }\n        };\n        Msvg.tagname = 'svg';\n        return Msvg;\n    }(Msvg_1.MsvgElement));\n    Msvg_1.Msvg = Msvg;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgDrawingElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    /**\n     * Base class for the Polyline and the Polygon (since they share so much)\n     */\n    var MsvgPolyElement = /** @class */ (function (_super) {\n        __extends(MsvgPolyElement, _super);\n        function MsvgPolyElement() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n        * points are written as following: x,y x2,y2 x3,y3 ...\n        */\n        MsvgPolyElement.prototype.setPoints = function (points) {\n            return this.setAttribute('points', points);\n        };\n        MsvgPolyElement.prototype.getPoints = function () {\n            return this.getAttribute('points');\n        };\n        /**\n         * clear all points\n         */\n        MsvgPolyElement.prototype.resetPoints = function () {\n            return this.setPoints(null);\n        };\n        /**\n         * add a point to the `points` attribute\n         */\n        MsvgPolyElement.prototype.addPoint = function (point) {\n            var pointsString = this.getPoints() || '';\n            if (pointsString.length) {\n                pointsString += ' ';\n            }\n            pointsString += point.x + ',' + point.y;\n            return this.setPoints(pointsString);\n        };\n        return MsvgPolyElement;\n    }(Msvg.MsvgDrawingElement));\n    Msvg.MsvgPolyElement = MsvgPolyElement;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgDrawingElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    /**\n     * Base class for shapes, e.g. rect ...\n     */\n    var MsvgShapeElement = /** @class */ (function (_super) {\n        __extends(MsvgShapeElement, _super);\n        function MsvgShapeElement() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        MsvgShapeElement.prototype.setPosition = function (position) {\n            this.setX(position.x);\n            return this.setY(position.y);\n        };\n        MsvgShapeElement.prototype.getPosition = function () {\n            var x = this.getX();\n            var y = this.getY();\n            return new Msvg.Point(x ? parseFloat(x) : null, y ? parseFloat(y) : null);\n        };\n        MsvgShapeElement.prototype.setX = function (x) {\n            return this.setAttribute('x', x);\n        };\n        MsvgShapeElement.prototype.getX = function () {\n            return this.getAttribute('x');\n        };\n        MsvgShapeElement.prototype.setY = function (y) {\n            return this.setAttribute('y', y);\n        };\n        MsvgShapeElement.prototype.getY = function () {\n            return this.getAttribute('y');\n        };\n        return MsvgShapeElement;\n    }(Msvg.MsvgDrawingElement));\n    Msvg.MsvgShapeElement = MsvgShapeElement;\n})(Msvg || (Msvg = {}));\nvar Msvg;\n(function (Msvg) {\n    var Utils;\n    (function (Utils) {\n        /**\n         * if you need to add multiple path commands at once to a path, use this class (or the path.createFastBuilder() method)\n         * and call finish after you have d\n         */\n        var PathFastBuilder = /** @class */ (function () {\n            function PathFastBuilder(path) {\n                this.path = path;\n                this.parts = [];\n            }\n            /**\n             * completely resets the path (nothing will be drawn) and makes it possible to start a new path\n             */\n            PathFastBuilder.prototype.reset = function () {\n                this.parts = [];\n                return this;\n            };\n            PathFastBuilder.prototype.finish = function () {\n                this.path.setD(this.parts.join(' '));\n                this.reset();\n                return this;\n            };\n            /**\n             * move to the target position without drawing anything\n             */\n            PathFastBuilder.prototype.addMoveToAbsolute = function (targetPosition) {\n                this.parts.push(PathFastBuilder.createMoveToAbsoluteCommand(targetPosition));\n                return this;\n            };\n            /**\n             * move to the target position without drawing anything\n             */\n            PathFastBuilder.prototype.addMoveToRelative = function (targetPosition) {\n                this.parts.push(PathFastBuilder.createMoveToRelativeCommand(targetPosition));\n                return this;\n            };\n            /**\n             * move to the target position with a simple line\n             */\n            PathFastBuilder.prototype.addLineToAbsolute = function (targetPosition) {\n                this.parts.push(PathFastBuilder.createLineToAbsoluteCommand(targetPosition));\n                return this;\n            };\n            /**\n             * move to the target position with a simple line\n             */\n            PathFastBuilder.prototype.addLineToRelative = function (targetPosition) {\n                this.parts.push(PathFastBuilder.createLineToRelativeCommand(targetPosition));\n                return this;\n            };\n            /**\n             * move to the target position with a simple line\n             *\n             * position is only the x coordinate\n             */\n            PathFastBuilder.prototype.addHorizontalLineToAbsolute = function (position) {\n                this.parts.push(PathFastBuilder.createHorizontalLineToAbsoluteCommand(position));\n                return this;\n            };\n            /**\n             * move to the target position with a simple line\n             *\n             * position is only the x coordinate\n             */\n            PathFastBuilder.prototype.addHorizontalLineToRelative = function (position) {\n                this.parts.push(PathFastBuilder.createHorizontalLineToRelativeCommand(position));\n                return this;\n            };\n            /**\n             * move to the target position with a simple line\n             *\n             * position is only the y coordinate\n             */\n            PathFastBuilder.prototype.addVerticalLineToAbsolute = function (position) {\n                this.parts.push(PathFastBuilder.createVerticalLineToAbsoluteCommand(position));\n                return this;\n            };\n            /**\n             * move to the target position with a simple line\n             *\n             * position is only the y coordinate\n             */\n            PathFastBuilder.prototype.addVerticalLineToRelative = function (position) {\n                this.parts.push(PathFastBuilder.createVerticalLineToRelativeCommand(position));\n                return this;\n            };\n            /**\n             * move to the target position in curve with two control points\n             */\n            PathFastBuilder.prototype.addCurveToAbsolute = function (targetPosition, controlPoint1, controlPoint2) {\n                this.parts.push(PathFastBuilder.createCurveToAbsoluteCommand(targetPosition, controlPoint1, controlPoint2));\n                return this;\n            };\n            /**\n             * move to the target position in curve with two control points\n             */\n            PathFastBuilder.prototype.addCurveToRelative = function (targetPosition, controlPoint1, controlPoint2) {\n                this.parts.push(PathFastBuilder.createCurveToRelativeCommand(targetPosition, controlPoint1, controlPoint2));\n                return this;\n            };\n            /**\n             * move to the target position in curve with one control points\n             */\n            PathFastBuilder.prototype.addSmoothCurveToAbsolute = function (targetPosition, controlPoint2) {\n                this.parts.push(PathFastBuilder.createSmoothCurveToAbsoluteCommand(targetPosition, controlPoint2));\n                return this;\n            };\n            /**\n             * move to the target position in curve with one control points\n             */\n            PathFastBuilder.prototype.addSmoothCurveToRelative = function (targetPosition, controlPoint2) {\n                this.parts.push(PathFastBuilder.createSmoothCurveToRelativeCommand(targetPosition, controlPoint2));\n                return this;\n            };\n            /**\n             * move to the target position in curve with one control point\n             */\n            PathFastBuilder.prototype.addQuadraticCurveToAbsolute = function (targetPosition, controlPoint1) {\n                this.parts.push(PathFastBuilder.createQuadraticCurveToAbsoluteCommand(targetPosition, controlPoint1));\n                return this;\n            };\n            /**\n             * move to the target position in curve with one control point\n             */\n            PathFastBuilder.prototype.addQuadraticCurveToRelative = function (targetPosition, controlPoint1) {\n                this.parts.push(PathFastBuilder.createQuadraticCurveToRelativeCommand(targetPosition, controlPoint1));\n                return this;\n            };\n            /**\n             * move to the target position in curve without control points\n             */\n            PathFastBuilder.prototype.addSmoothQuadraticCurveToAbsolute = function (targetPosition) {\n                this.parts.push(PathFastBuilder.createSmoothQuadraticCurveToAbsoluteCommand(targetPosition));\n                return this;\n            };\n            /**\n             * move to the target position in curve without control points\n             */\n            PathFastBuilder.prototype.addSmoothQuadraticCurveToRelative = function (targetPosition) {\n                this.parts.push(PathFastBuilder.createSmoothQuadraticCurveToRelativeCommand(targetPosition));\n                return this;\n            };\n            /**\n             * move to the target position in a eliptical arc\n             *\n             *\n             * @param targetPosition\n             * @param radiuses x and y radius of the ellipse (for a circle: rx = ry)\n             * @param rotation x rotation of the ellipse\n             * @param largeArcFlag arc should be greater or less than 180 deg\n             * @param sweepFlag begin moving at a negative or positive angle\n             */\n            PathFastBuilder.prototype.addArcToAbsolute = function (targetPosition, radiuses, rotation, largeArcFlag, sweepFlag) {\n                this.parts.push(PathFastBuilder.createArcToAbsoluteCommand(targetPosition, radiuses, rotation, largeArcFlag, sweepFlag));\n                return this;\n            };\n            /**\n             * move to the target position in a eliptical arc\n             *\n             *\n             * @param targetPosition\n             * @param radiuses x and y radius of the ellipse (for a circle: rx = ry)\n             * @param rotation x rotation of the ellipse\n             * @param largeArcFlag arc should be greater or less than 180 deg\n             * @param sweepFlag begin moving at a negative or positive angle\n             */\n            PathFastBuilder.prototype.addArcToRelative = function (targetPosition, radiuses, rotation, largeArcFlag, sweepFlag) {\n                this.parts.push(PathFastBuilder.createArcToRelativeCommand(targetPosition, radiuses, rotation, largeArcFlag, sweepFlag));\n                return this;\n            };\n            PathFastBuilder.prototype.addClosePath = function () {\n                this.parts.push(PathFastBuilder.createClosePathCommand());\n                return this;\n            };\n            PathFastBuilder.createMoveToAbsoluteCommand = function (targetPosition) {\n                return 'M' + targetPosition.toString();\n            };\n            PathFastBuilder.createMoveToRelativeCommand = function (targetPosition) {\n                return 'm' + targetPosition.toString();\n            };\n            PathFastBuilder.createLineToAbsoluteCommand = function (targetPosition) {\n                return 'L' + targetPosition.toString();\n            };\n            PathFastBuilder.createLineToRelativeCommand = function (targetPosition) {\n                return 'l' + targetPosition.toString();\n            };\n            PathFastBuilder.createHorizontalLineToAbsoluteCommand = function (position) {\n                return 'H' + position;\n            };\n            PathFastBuilder.createHorizontalLineToRelativeCommand = function (position) {\n                return 'h' + position;\n            };\n            PathFastBuilder.createVerticalLineToAbsoluteCommand = function (position) {\n                return 'V' + position;\n            };\n            PathFastBuilder.createVerticalLineToRelativeCommand = function (position) {\n                return 'v' + position;\n            };\n            PathFastBuilder.createCurveToAbsoluteCommand = function (targetPosition, controlPoint1, controlPoint2) {\n                return 'C' + controlPoint1.toString() + ' ' + controlPoint2.toString() + ' ' + targetPosition.toString();\n            };\n            PathFastBuilder.createCurveToRelativeCommand = function (targetPosition, controlPoint1, controlPoint2) {\n                return 'c' + controlPoint1.toString() + ' ' + controlPoint2.toString() + ' ' + targetPosition.toString();\n            };\n            PathFastBuilder.createSmoothCurveToAbsoluteCommand = function (targetPosition, controlPoint2) {\n                return 'S' + controlPoint2.toString() + ' ' + targetPosition.toString();\n            };\n            PathFastBuilder.createSmoothCurveToRelativeCommand = function (targetPosition, controlPoint2) {\n                return 's' + controlPoint2.toString() + ' ' + targetPosition.toString();\n            };\n            PathFastBuilder.createQuadraticCurveToAbsoluteCommand = function (targetPosition, controlPoint1) {\n                return 'Q' + controlPoint1.toString() + ' ' + targetPosition.toString();\n            };\n            PathFastBuilder.createQuadraticCurveToRelativeCommand = function (targetPosition, controlPoint1) {\n                return 'q' + controlPoint1.toString() + ' ' + targetPosition.toString();\n            };\n            PathFastBuilder.createSmoothQuadraticCurveToAbsoluteCommand = function (targetPosition) {\n                return 'T' + targetPosition.toString();\n            };\n            PathFastBuilder.createSmoothQuadraticCurveToRelativeCommand = function (targetPosition) {\n                return 't' + targetPosition.toString();\n            };\n            PathFastBuilder.createArcToAbsoluteCommand = function (targetPosition, radiuses, rotation, largeArcFlag, sweepFlag) {\n                return 'A' + this.createArcPath(targetPosition, radiuses, rotation, largeArcFlag, sweepFlag);\n            };\n            PathFastBuilder.createArcToRelativeCommand = function (targetPosition, radiuses, rotation, largeArcFlag, sweepFlag) {\n                return 'a' + this.createArcPath(targetPosition, radiuses, rotation, largeArcFlag, sweepFlag);\n            };\n            PathFastBuilder.createArcPath = function (targetPosition, radiuses, rotation, largeArcFlag, sweepFlag) {\n                return radiuses.toString() + ' ' + rotation + ' ' + (largeArcFlag ? '1' : '0') + ' ' + (sweepFlag ? '1' : '0') + ' ' + targetPosition.toString();\n            };\n            PathFastBuilder.createClosePathCommand = function () {\n                return 'Z';\n            };\n            return PathFastBuilder;\n        }());\n        Utils.PathFastBuilder = PathFastBuilder;\n    })(Utils = Msvg.Utils || (Msvg.Utils = {}));\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgDrawingElement.ts\" />\n/// <reference path=\"./Utils/PathFastBuilder.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var PathFastBuilder = Msvg.Utils.PathFastBuilder;\n    var Path = /** @class */ (function (_super) {\n        __extends(Path, _super);\n        function Path() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * set the path (coordinates)\n         */\n        Path.prototype.setD = function (d) {\n            return this.setAttribute('d', d);\n        };\n        Path.prototype.getD = function () {\n            return this.getAttribute('d');\n        };\n        Path.prototype.createFastBuilder = function () {\n            return new PathFastBuilder(this);\n        };\n        /**\n         * completely resets the path (nothing will be drawn) and makes it possible to start a new path\n         */\n        Path.prototype.reset = function () {\n            return this.setD(null);\n        };\n        /**\n         * move to the target position without drawing anything\n         */\n        Path.prototype.addMoveToAbsolute = function (targetPosition) {\n            return this.appendToD(PathFastBuilder.createMoveToAbsoluteCommand(targetPosition));\n        };\n        /**\n         * move to the target position without drawing anything\n         */\n        Path.prototype.addMoveToRelative = function (targetPosition) {\n            return this.appendToD(PathFastBuilder.createMoveToRelativeCommand(targetPosition));\n        };\n        /**\n         * move to the target position with a simple line\n         */\n        Path.prototype.addLineToAbsolute = function (targetPosition) {\n            return this.appendToD(PathFastBuilder.createLineToAbsoluteCommand(targetPosition));\n        };\n        /**\n         * move to the target position with a simple line\n         */\n        Path.prototype.addLineToRelative = function (targetPosition) {\n            return this.appendToD(PathFastBuilder.createLineToRelativeCommand(targetPosition));\n        };\n        /**\n         * move to the target position with a simple line\n         *\n         * position is only the x coordinate\n         */\n        Path.prototype.addHorizontalLineToAbsolute = function (position) {\n            return this.appendToD(PathFastBuilder.createHorizontalLineToAbsoluteCommand(position));\n        };\n        /**\n         * move to the target position with a simple line\n         *\n         * position is only the x coordinate\n         */\n        Path.prototype.addHorizontalLineToRelative = function (position) {\n            return this.appendToD(PathFastBuilder.createHorizontalLineToRelativeCommand(position));\n        };\n        /**\n         * move to the target position with a simple line\n         *\n         * position is only the y coordinate\n         */\n        Path.prototype.addVerticalLineToAbsolute = function (position) {\n            return this.appendToD(PathFastBuilder.createVerticalLineToAbsoluteCommand(position));\n        };\n        /**\n         * move to the target position with a simple line\n         *\n         * position is only the y coordinate\n         */\n        Path.prototype.addVerticalLineToRelative = function (position) {\n            return this.appendToD(PathFastBuilder.createVerticalLineToRelativeCommand(position));\n        };\n        /**\n         * move to the target position in curve with two control points\n         */\n        Path.prototype.addCurveToAbsolute = function (targetPosition, controlPoint1, controlPoint2) {\n            return this.appendToD(PathFastBuilder.createCurveToAbsoluteCommand(targetPosition, controlPoint1, controlPoint2));\n        };\n        /**\n         * move to the target position in curve with two control points\n         */\n        Path.prototype.addCurveToRelative = function (targetPosition, controlPoint1, controlPoint2) {\n            return this.appendToD(PathFastBuilder.createCurveToRelativeCommand(targetPosition, controlPoint1, controlPoint2));\n        };\n        /**\n         * move to the target position in curve with one control points\n         */\n        Path.prototype.addSmoothCurveToAbsolute = function (targetPosition, controlPoint2) {\n            return this.appendToD(PathFastBuilder.createSmoothCurveToAbsoluteCommand(targetPosition, controlPoint2));\n        };\n        /**\n         * move to the target position in curve with one control points\n         */\n        Path.prototype.addSmoothCurveToRelative = function (targetPosition, controlPoint2) {\n            return this.appendToD(PathFastBuilder.createSmoothCurveToRelativeCommand(targetPosition, controlPoint2));\n        };\n        /**\n         * move to the target position in curve with one control point\n         */\n        Path.prototype.addQuadraticCurveToAbsolute = function (targetPosition, controlPoint1) {\n            return this.appendToD(PathFastBuilder.createQuadraticCurveToAbsoluteCommand(targetPosition, controlPoint1));\n        };\n        /**\n         * move to the target position in curve with one control point\n         */\n        Path.prototype.addQuadraticCurveToRelative = function (targetPosition, controlPoint1) {\n            return this.appendToD(PathFastBuilder.createQuadraticCurveToRelativeCommand(targetPosition, controlPoint1));\n        };\n        /**\n         * move to the target position in curve without control points\n         */\n        Path.prototype.addSmoothQuadraticCurveToAbsolute = function (targetPosition) {\n            return this.appendToD(PathFastBuilder.createSmoothQuadraticCurveToAbsoluteCommand(targetPosition));\n        };\n        /**\n         * move to the target position in curve without control points\n         */\n        Path.prototype.addSmoothQuadraticCurveToRelative = function (targetPosition) {\n            return this.appendToD(PathFastBuilder.createSmoothQuadraticCurveToRelativeCommand(targetPosition));\n        };\n        /**\n         * move to the target position in a eliptical arc\n         *\n         *\n         * @param targetPosition\n         * @param radiuses x and y radius of the ellipse (for a circle: rx = ry)\n         * @param rotation x rotation of the ellipse\n         * @param largeArcFlag arc should be greater or less than 180 deg\n         * @param sweepFlag begin moving at a negative or positive angle\n         */\n        Path.prototype.addArcToAbsolute = function (targetPosition, radiuses, rotation, largeArcFlag, sweepFlag) {\n            return this.appendToD(PathFastBuilder.createArcToAbsoluteCommand(targetPosition, radiuses, rotation, largeArcFlag, sweepFlag));\n        };\n        /**\n         * move to the target position in a eliptical arc\n         *\n         *\n         * @param targetPosition\n         * @param radiuses x and y radius of the ellipse (for a circle: rx = ry)\n         * @param rotation x rotation of the ellipse\n         * @param largeArcFlag arc should be greater or less than 180 deg\n         * @param sweepFlag begin moving at a negative or positive angle\n         */\n        Path.prototype.addArcToRelative = function (targetPosition, radiuses, rotation, largeArcFlag, sweepFlag) {\n            return this.appendToD(PathFastBuilder.createArcToRelativeCommand(targetPosition, radiuses, rotation, largeArcFlag, sweepFlag));\n        };\n        Path.prototype.addClosePath = function () {\n            return this.appendToD(PathFastBuilder.createClosePathCommand());\n        };\n        /**\n         * if `d` is already set, add a trailing space and return it\n         */\n        Path.prototype.appendToD = function (str) {\n            var d = this.getD();\n            d = d ? d + ' ' : '';\n            return this.setD(d + str);\n        };\n        Path.tagname = 'path';\n        return Path;\n    }(Msvg.MsvgDrawingElement));\n    Msvg.Path = Path;\n})(Msvg || (Msvg = {}));\nvar Msvg;\n(function (Msvg) {\n    var Point = /** @class */ (function () {\n        function Point(x, y) {\n            this.x = x;\n            this.y = y;\n        }\n        /**\n         * creates a new Point which is the result of adding `this` and `point`\n         */\n        Point.prototype.add = function (point) {\n            return new Point(this.x + point.x, this.y + point.y);\n        };\n        /**\n         * creates a new Point which is the result of substracting `this` and `point`\n         */\n        Point.prototype.sub = function (point) {\n            return new Point(this.x - point.x, this.y - point.y);\n        };\n        /**\n         * returns a space seperated cordinate (`x y`)\n         */\n        Point.prototype.toString = function () {\n            return this.x + ' ' + this.y;\n        };\n        /**\n         * check if the coordinates of `this` equals those of `point`\n         */\n        Point.prototype.equals = function (point) {\n            return this.x == point.x && this.y == point.y;\n        };\n        return Point;\n    }());\n    Msvg.Point = Point;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgPolyElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Polygon = /** @class */ (function (_super) {\n        __extends(Polygon, _super);\n        function Polygon() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        Polygon.tagname = 'polygon';\n        return Polygon;\n    }(Msvg.MsvgPolyElement));\n    Msvg.Polygon = Polygon;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgPolyElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Polyline = /** @class */ (function (_super) {\n        __extends(Polyline, _super);\n        function Polyline() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        Polyline.tagname = 'polyline';\n        return Polyline;\n    }(Msvg.MsvgPolyElement));\n    Msvg.Polyline = Polyline;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgShapeElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Rectangle = /** @class */ (function (_super) {\n        __extends(Rectangle, _super);\n        function Rectangle() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        /**\n         * width, relative to the position (which is on the top left)\n         */\n        Rectangle.prototype.setWidth = function (width) {\n            return this.setAttribute('width', width);\n        };\n        Rectangle.prototype.getWidth = function () {\n            return this.getAttribute('width');\n        };\n        /**\n         * height, relative to the position (which is on the top left)\n         */\n        Rectangle.prototype.setHeight = function (height) {\n            return this.setAttribute('height', height);\n        };\n        Rectangle.prototype.getHeight = function () {\n            return this.getAttribute('height');\n        };\n        /**\n         * x radius for rounded corners\n         */\n        Rectangle.prototype.setRx = function (rx) {\n            return this.setAttribute('rx', rx);\n        };\n        Rectangle.prototype.getRx = function () {\n            return this.getAttribute('rx');\n        };\n        /**\n         * y radius for rounded corners\n         */\n        Rectangle.prototype.setRy = function (ry) {\n            return this.setAttribute('ry', ry);\n        };\n        Rectangle.prototype.getRy = function () {\n            return this.getAttribute('ry');\n        };\n        Rectangle.tagname = 'rect';\n        return Rectangle;\n    }(Msvg.MsvgShapeElement));\n    Msvg.Rectangle = Rectangle;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"./MsvgShapeElement.ts\" />\nvar Msvg;\n(function (Msvg) {\n    var Text = /** @class */ (function (_super) {\n        __extends(Text, _super);\n        function Text(element) {\n            var _this = _super.call(this, element) || this;\n            _this.textNodeConstructor = (document.createTextNode('')).constructor;\n            _this.spans = [];\n            _this.setFontSize(16);\n            return _this;\n        }\n        Text.prototype.setText = function (text) {\n            this.empty();\n            this.spans = [];\n            if (text === '') {\n                return;\n            }\n            var lines = text.split('\\n');\n            for (var key = 0; key < lines.length; key++) {\n                this.addSpanForLine(lines[key]);\n            }\n            this.updateSpanPositions();\n            return this;\n        };\n        Text.prototype.getText = function () {\n            var _this = this;\n            var texts = this.spans.map(function (span) {\n                return _this.concatNodesTexts(span.childNodes);\n            });\n            return texts.join('\\n');\n        };\n        Text.prototype.setX = function (x) {\n            _super.prototype.setX.call(this, x);\n            this.updateSpanPositions();\n            return this;\n        };\n        Text.prototype.setY = function (y) {\n            _super.prototype.setY.call(this, y);\n            this.updateSpanPositions();\n            return this;\n        };\n        Text.prototype.setFontSize = function (size) {\n            this.setAttribute('font-size', size);\n            this.updateSpanPositions();\n            return this;\n        };\n        Text.prototype.getFontSize = function () {\n            var fontSize = parseFloat(this.getAttribute('font-size'));\n            return isNaN(fontSize) ? null : fontSize;\n        };\n        Text.prototype.getHeight = function () {\n            return this.spans.length * this.getLineHeight();\n        };\n        Text.prototype.getLineHeight = function () {\n            return this.getFontSize() || 0;\n        };\n        Text.prototype.concatNodesTexts = function (nodes) {\n            var text = '';\n            for (var key = 0; key < nodes.length; key++) {\n                var node = nodes[key];\n                if (node.constructor === this.textNodeConstructor) {\n                    text += node.nodeValue;\n                }\n            }\n            return text;\n        };\n        Text.prototype.addSpanForLine = function (text) {\n            var span = Msvg.Msvg.createSvgElement('tspan');\n            span.appendChild(document.createTextNode(text));\n            this.spans.push(span);\n            this.element.appendChild(span);\n        };\n        Text.prototype.updateSpanPositions = function () {\n            var fontSize = this.getFontSize() || 0;\n            var lineHeight = this.getLineHeight();\n            var startPoint = this.getPosition();\n            startPoint.y += fontSize; //because the tspan position is on the bottom left (and not top left)\n            this.spans.forEach(function (span, index) {\n                span.setAttribute('x', String(startPoint.x));\n                span.setAttribute('y', String(startPoint.y + index * lineHeight));\n            });\n        };\n        Text.tagname = 'text';\n        return Text;\n    }(Msvg.MsvgShapeElement));\n    Msvg.Text = Text;\n})(Msvg || (Msvg = {}));\n/// <reference path=\"../Point.ts\"/>\nvar Msvg;\n(function (Msvg) {\n    var Utils;\n    (function (Utils) {\n        var Bounds = /** @class */ (function () {\n            function Bounds(points) {\n                if (!points || points.length === 0) {\n                    throw new Error('[Msvg.Utils.Bounds] the points argument is required and has to contain atleast 1 Point');\n                }\n                this.points = points;\n                this.recalculate();\n            }\n            Bounds.prototype.getTopLeftCorner = function () {\n                return this.topLeftCorner;\n            };\n            Bounds.prototype.getTopRightCorner = function () {\n                return this.topRightCorner;\n            };\n            Bounds.prototype.getBottomLeftCorner = function () {\n                return this.bottomLeftCorner;\n            };\n            Bounds.prototype.getBottomRightCorner = function () {\n                return this.bottomRightCorner;\n            };\n            /**\n             * x = width, y = height\n             */\n            Bounds.prototype.getSize = function () {\n                return this.size;\n            };\n            Bounds.prototype.addPoint = function (point) {\n                this.points.push(point);\n                this.recalculate();\n            };\n            Bounds.prototype.recalculate = function () {\n                var minMaxInfo = this.calculateMinMaxInfo();\n                this.topLeftCorner = new Msvg.Point(minMaxInfo.minX, minMaxInfo.minY);\n                this.topRightCorner = new Msvg.Point(minMaxInfo.maxX, minMaxInfo.minY);\n                this.bottomLeftCorner = new Msvg.Point(minMaxInfo.minX, minMaxInfo.maxY);\n                this.bottomRightCorner = new Msvg.Point(minMaxInfo.maxX, minMaxInfo.maxY);\n                this.size = new Msvg.Point(this.bottomRightCorner.x - this.topLeftCorner.x, this.bottomRightCorner.y - this.topLeftCorner.y);\n            };\n            Bounds.prototype.calculateMinMaxInfo = function () {\n                var firstPoint = this.points[0];\n                var minX = firstPoint.x;\n                var minY = firstPoint.y;\n                var maxX = firstPoint.x;\n                var maxY = firstPoint.y;\n                for (var key = 1; key < this.points.length; key++) {\n                    var point = this.points[key];\n                    minX = Math.min(point.x, minX);\n                    minY = Math.min(point.y, minY);\n                    maxX = Math.max(point.x, maxX);\n                    maxY = Math.max(point.y, maxY);\n                }\n                return { minX: minX, minY: minY, maxX: maxX, maxY: maxY };\n            };\n            return Bounds;\n        }());\n        Utils.Bounds = Bounds;\n    })(Utils = Msvg.Utils || (Msvg.Utils = {}));\n})(Msvg || (Msvg = {}));\nvar Msvg;\n(function (Msvg) {\n    var Utils;\n    (function (Utils) {\n        var Definitions = /** @class */ (function () {\n            function Definitions() {\n            }\n            Definitions.svgNamespace = 'http://www.w3.org/2000/svg';\n            Definitions.xlinkNamespace = 'http://www.w3.org/1999/xlink';\n            return Definitions;\n        }());\n        Utils.Definitions = Definitions;\n    })(Utils = Msvg.Utils || (Msvg.Utils = {}));\n})(Msvg || (Msvg = {}));\nwindow.Msvg = Msvg;\n//# sourceMappingURL=msvg.js.map\n","// Module\nvar code = \"<template class=\\\"css-bar-chart-bar ${ multi ? 'css-bar-chart-bar--multi' : 'css-bar-chart-bar--single' }\\\" style.to-view=\\\"{ '--css-bar-chart-bar-height': valueConfig.value + '%' }\\\"> <x-tooltip attach-to.to-view=\\\"chartElement\\\" boundary-element.to-view=\\\"chartElement\\\" for-element.to-view=\\\"domElement\\\" hover-element.to-view=\\\"barWrapperElement\\\">${valueConfig.tooltip}</x-tooltip> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"css-bar-chart\\\" style.to-view=\\\"{ '--css-bar-chart-column-width': columnsDomElement.clientWidth + 'px' }\\\"> <div class=\\\"css-bar-chart__rows\\\"> <div class=\\\"css-bar-chart__y-axis-ticks\\\"> <div repeat.for=\\\"yTick of yTicks\\\" class=\\\"css-bar-chart__y-axis-tick-label\\\" style.to-view=\\\"{ bottom: $index * 25 + '%' }\\\">${yTick}</div> <div class=\\\"css-bar-chart__y-axis-marker css-bar-chart__success-marker\\\" style.to-view=\\\"{ bottom: successThresholdValue + '%' }\\\"></div> </div> <div if.to-view=\\\"showScrollOffset\\\" class=\\\"css-bar-chart__scroll-offset\\\"></div> </div> <div class=\\\"css-bar-chart__columns\\\" ref=\\\"columnsDomElement\\\"> <div repeat.for=\\\"xDataGroup of barChartConfig\\\" class=\\\"css-bar-chart__bar-group\\\" style.to-view=\\\"{ '--css-bar-chart-max-group-size': maxGroupSize }\\\"> <div class=\\\"css-bar-chart__bars\\\"> <div repeat.for=\\\"valueConfig of xDataGroup.values\\\" class=\\\"css-bar-chart__bar-wrapper\\\" ref=\\\"barWrapperElements[$index]\\\"> <css-bar-chart-bar value-config.to-view=\\\"valueConfig\\\" multi.to-view=\\\"xDataGroup.values.length > 1\\\" chart-element.to-view=\\\"chartElement\\\" bar-wrapper-element.to-view=\\\"barWrapperElements[$index]\\\"></css-bar-chart-bar> </div> </div> <div class=\\\"css-bar-chart__bar-group-label\\\">${xDataGroup.label}</div> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"custom-select-answer-overlay\\\"> <full-screen-container view-model.ref=\\\"fullScreenContainer\\\" animation-player.to-view=\\\"animationPlayer\\\"> <div ref=\\\"contentWrapperElement\\\" class=\\\"dialog__content-wrapper custom-select-answer-overlay__content-wrapper\\\"> <div ref=\\\"contentElement\\\" class=\\\"custom-select-answer-overlay__container dialog__content\\\"> <h3 class=\\\"custom-select-answer-overlay__headline dialog__title\\\" t=\\\"resources.elements.custom-select-answer-overlay.chooseAnswer\\\"></h3> <div class=\\\"custom-select-answer-overlay__separator\\\"></div> <div class=\\\"custom-select-answer-overlay__scroll-wrap\\\"> <list-standard class=\\\"custom-select-answer-overlay__list\\\" items.to-view=\\\"selectItems\\\"></list-standard> </div> <div class=\\\"custom-select-answer-overlay__separator\\\"></div> <footer class=\\\"dialog__btn-box custom-select-answer-overlay__footer\\\"> <button-standard btn-type=\\\"text\\\" class=\\\"custom-select-answer-overlay__button\\\" click.delegate=\\\"cancel()\\\" t=\\\"[btnText]resources.elements.custom-select-answer-overlay.cancel\\\"></button-standard> <button-standard btn-type=\\\"text\\\" click.delegate=\\\"confirmAnswer()\\\" class=\\\"custom-select-answer-overlay__button\\\" t=\\\"[btnText]resources.elements.custom-select-answer-overlay.select\\\"></button-standard> </footer> </div> </div> </full-screen-container> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"distinar-conference-student-view ${ showVideo ? `distinar-conference-student-view--show-video` : `` }\\\" click.delegate=\\\"toggleHideMenus()\\\"> <conference-video-matrix if.to-view=\\\"showVideo && !isMock\\\" class=\\\"distinar-conference-student-view__matrix\\\" show-content-share.to-view=\\\"true\\\" tenant-logo-picture-url.to-view=\\\"tenantTheme.logoPictureUrl\\\" tenant-name.to-view=\\\"tenantTheme.name\\\"></conference-video-matrix> <div if.to-view=\\\"showVideo && isMock\\\" class=\\\"distinar-conference-student-view__matrix-mock\\\"> <div repeat.for=\\\"i of 9\\\" class=\\\"distinar-conference-student-view__matrix-mock-video\\\"> <safe-icon class=\\\"distinar-conference-student-view__matrix-mock-video-icon\\\" icon-name=\\\"Distinar/LecturerCam\\\"></safe-icon> </div> </div> <lecture-status if.to-view=\\\"!showVideo\\\" class=\\\"distinar-conference-student-view__status\\\" t.to-view=\\\"statusInfo\\\" active-lecture.to-view=\\\"activeLecture\\\" tenant-logo-picture-url.to-view=\\\"tenantLogoPictureUrl\\\"></lecture-status> <distinar-floating-video-container if.to-view=\\\"localAttendeeId != null\\\" floating-corner=\\\"bottom-left\\\"> <conference-attendee chime-attendee-id.to-view=\\\"localAttendeeId\\\"></conference-attendee> </distinar-floating-video-container> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"distinar-course-picture-overlay ${isOpen ? `distinar-course-picture-overlay--open` : ``} ${canZoomOut ? `distinar-course-picture-overlay--zoom-out` : ``}\\\" click.trigger=\\\"handleZoomOut()\\\"> <aspect-ratio-container class=\\\"distinar-course-picture-overlay__aspect-ratio-container\\\" mode=\\\"width-and-height-dependent\\\" ratio.to-view=\\\"pictureRatio\\\"> <img class=\\\"distinar-course-picture-overlay__picture\\\" src.to-view=\\\"block.picture.url\\\"> </aspect-ratio-container> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"distinar-floating-video-container distinar-floating-video-container__mode--${floatingCorner}\\\" style.to-view=\\\"{ '--distinar-floating-video-container-width': width }\\\"> <aspect-ratio-container ratio.to-view=\\\"4/3\\\"> <slot></slot> </aspect-ratio-container> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"distinar-whiteboard-viewer\\\" style.to-view=\\\"backgroundColor ? { 'background-color': backgroundColor } : {}\\\"> <img if.to-view=\\\"showWhiteboard\\\" class=\\\"distinar-whiteboard-viewer__svg\\\" src.to-view=\\\"svgData\\\"> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"donut-chart donut-chart--${color}\\\"> <svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" x=\\\"0px\\\" y=\\\"0px\\\" viewBox=\\\"0 0 ${donutDiameter} ${donutDiameter}\\\" enable-background=\\\"new 0 0 ${donutDiameter} ${donutDiameter}\\\" xml:space=\\\"preserve\\\" class=\\\"donut-chart__svg\\\"> <linearGradient id=\\\"${idPrimary}\\\"> <stop class=\\\"donut-chart__gradient-start-primary\\\" offset=\\\"0%\\\"></stop> <stop class=\\\"donut-chart__gradient-end-primary\\\" offset=\\\"100%\\\"></stop> </linearGradient> <linearGradient id=\\\"${idSecondary}\\\"> <stop class=\\\"donut-chart__gradient-start-secondary\\\" offset=\\\"0%\\\"></stop> <stop class=\\\"donut-chart__gradient-end-secondary\\\" offset=\\\"100%\\\"></stop> </linearGradient> <text if.to-view=\\\"showValueText\\\" font-size.to-view=\\\"(hidePercentage ? 60 : 45) * fontScale\\\" text-anchor=\\\"middle\\\" class=\\\"donut-chart__text\\\" dominant-baseline=\\\"central\\\" x=\\\"50%\\\" y=\\\"50%\\\" data-test-selector=\\\"donut-chart-value\\\">${formatValue(value)}${hidePercentage ? '' : '%'}</text> <g transform=\\\"translate(${donutOuterRadius}, ${donutOuterRadius})\\\"> <circle r=\\\"${donutInnerRadius}\\\" stroke-width=\\\"${donutStrokeWidth}\\\" class=\\\"donut-chart__circle-back\\\"/> <circle r=\\\"${donutInnerRadius}\\\" stroke-dasharray=\\\"${circleFrontStrokeDash}\\\" stroke-dashoffset.bind=\\\"getCircleFrontStrokeDashOffset(value)\\\" stroke-width=\\\"${donutStrokeWidth}\\\" stroke=\\\"url(#${color === chartColorEnum.Primary ? idPrimary : idSecondary })\\\" class=\\\"donut-chart__circle-front\\\" transform=\\\"rotate(275.1)\\\"/> </g> </svg> <x-icon if.to-view=\\\"!showValueText && !hideDisplay && isFull\\\" class=\\\"donut-chart__icon\\\" size=\\\"unspecified\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Check\\\" data-test-selector=\\\"donut-chart-icon\\\"> </x-icon> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \" <template> <div class=\\\"drawing-area--ContentWrapper\\\" css.bind=\\\"_getContentWrapperStyle(_ratio)\\\"> <svg ref=\\\"_svgElement\\\" class=\\\"drawing-area--SvgElement\\\" click.trigger=\\\"_handleDrawingAreaClick($event)\\\" mousemove.trigger=\\\"_handleDrawingAreaMousemove($event)\\\" mouseenter.trigger=\\\"_handleDrawingAreaMouseenter($event)\\\" mouseleave.trigger=\\\"_handleDrawingAreaMouseleave($event)\\\" mousedown.trigger=\\\"_handleDrawingAreaMousedown($event)\\\" mouseup.trigger=\\\"_handleDrawingAreaMouseup($event)\\\" touchstart.trigger=\\\"_handleDrawingAreaTouchstart($event)\\\" touchmove.trigger=\\\"_handleDrawingAreaTouchmove($event)\\\" touchend.trigger=\\\"_handleDrawingAreaTouchend($event)\\\"></svg> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mdc-list-item__text\\\"> <span if.to-view=\\\"usePropertyNameTk\\\" t.to-view=\\\"selectItem[propertyNameTk]\\\"></span> <span if.to-view=\\\"usePropertyName\\\">${selectItem[propertyName]}</span> <span if.to-view=\\\"useFallbackTk\\\" t.to-view=\\\"fallbackTk\\\" t-params.to-view=\\\"params\\\"></span> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mdc-select mdc-select--no-label mdc-text-field--outlined mdc-select--outlined dropdown-select dropdown-select--${selectStyle} dropdown-select--${selectSize} ${ disabled ? 'mdc-select--disabled dropdown-select--disabled' : '' } ${ error ? 'dropdown-select--error' : '' }\\\" role=\\\"menubar\\\" aria-haspopup=\\\"true\\\" aria-expanded.to-view=\\\"menu.open\\\" aria-labelledby=\\\"dropdown-select-label-${id}\\\"> <div class=\\\"mdc-select__anchor dropdown-select__anchor\\\" ref=\\\"dropdownAnchorElement\\\" click.trigger=\\\"dropdownFocused()\\\"> <div class=\\\"mdc-notched-outline mdc-text-field--outlined dropdown-select__notched-outline\\\" ref=\\\"dropdownOutlineElement\\\"> <div class=\\\"mdc-notched-outline__leading\\\"></div> <div class=\\\"mdc-notched-outline__notch\\\"> <label ref=\\\"dropdownLabelElement\\\" id=\\\"dropdown-select-label-${id}\\\" class=\\\"mdc-floating-label mdc-floating-label--float-above dropdown-select__label ${ selectedItem ? 'dropdown-select__label--float-above' : '' }\\\">${outlineLabel}</label> </div> <div class=\\\"mdc-notched-outline__trailing\\\"></div> </div> <x-icon class=\\\"dropdown-select__icon mdc-select__icon\\\" size.to-view=\\\"selectStyle === `distinar-filled` ? `unspecified` : `normal`\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Tabler/Chevron-Down\\\"> </x-icon> <div class=\\\"mdc-select__selected-text dropdown-select__text\\\" aria-disabled=\\\"disabled\\\" data-value=\\\"${selectedItem[valuePropertyName]}\\\"> <dropdown-select-label if.to-view=\\\"selectItems.length > 0\\\" select-item.to-view=\\\"selectedItem\\\" property-name.to-view=\\\"labelPropertyName\\\" property-name-tk.to-view=\\\"labelPropertyNameTk\\\" fallback-tk.to-view=\\\"labelFallbackTk\\\"></dropdown-select-label> <span if.to-view=\\\"selectItems.length === 0 && noSelectionTk\\\" t.to-view=\\\"noSelectionTk\\\"></span> </div> </div> <div ref=\\\"dropdownMenuElement\\\" class=\\\"mdc-select__menu mdc-menu mdc-menu-surface dropdown-select__menu ${ autoMenu ? '' : 'mdc-select__menu--fixed-to-bottom' } ${ fixedMenu ? 'mdc-menu-surface--fixed' : '' }\\\"> <ul class=\\\"mdc-list dropdown-select__list\\\" role=\\\"menu\\\" aria-hidden=\\\"true\\\" aria-orientation=\\\"vertical\\\" tabindex=\\\"-1\\\" aria-labelledby=\\\"dropdown-select-label-${id}\\\"> <li if.to-view=\\\"select\\\" repeat.for=\\\"selectItem of selectItems\\\" role=\\\"menuitem\\\" class=\\\"mdc-list-item dropdown-select__list-item ${ selectItem[valuePropertyName] == selectedItem[valuePropertyName] ? 'mdc-list-item--selected' : '' }\\\" data-value=\\\"${selectItem[valuePropertyName] == selectedItem[valuePropertyName] ? selectedItem[valuePropertyName] : selectItem[valuePropertyName]}\\\"> <dropdown-select-label select-item.to-view=\\\"selectItem\\\" tabindex=\\\"-1\\\" property-name.to-view=\\\"labelPropertyName\\\" property-name-tk.to-view=\\\"labelPropertyNameTk\\\" fallback-tk.to-view=\\\"labelFallbackTk\\\" params.to-view=\\\"{ index: $index }\\\"></dropdown-select-label> </li> </ul> </div> </template>\";\n// Exports\nexport default code;","import { PLATFORM, autoinject, bindable, useView } from 'aurelia-framework';\nimport { ICssBarChartValueConfig } from '../css-bar-chart/css-bar-chart';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./css-bar-chart-bar.html'))\nexport class CssBarChartBar {\n  @bindable() public valueConfig: ICssBarChartValueConfig | null = null;\n  @bindable() public barWrapperElement: HTMLElement | null = null;\n  @bindable() public chartElement: HTMLElement | null = null;\n  @bindable() public multi: boolean = false;\n\n  private domElement: HTMLElement;\n\n  constructor(\n    element: Element,\n  ) {\n    this.domElement = element as HTMLElement;\n  }\n}","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/css-bar-chart-bar/css-bar-chart-bar'));\n}\n","import { PLATFORM, autoinject, useView, bindable } from 'aurelia-framework';\nimport { SubscriptionManager, SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\n\nexport interface ICssBarChartValueConfig {\n  tooltip: string;\n  value: number;\n}\n\nexport interface ICssBarChartConfig {\n  label: string;\n  values: ICssBarChartValueConfig[];\n}\n\n@autoinject()\n@useView(PLATFORM.moduleName('./css-bar-chart.html'))\nexport class CssBarChart {\n  @bindable() public barChartConfig: ICssBarChartConfig[] = [];\n  private yTicks: string[] = ['0%', '25%', '50%', '75%', '100%'];\n  private successThresholdValue: number = 80;\n  private showScrollOffset: boolean = false;\n\n  private subscriptionManager: SubscriptionManager;\n  private columnsDomElement: HTMLElement | null = null;\n  private barWrapperElements: HTMLElement[] = [];\n  private chartElement: HTMLElement | null = null;\n\n  constructor(\n    subscriptionManagerService: SubscriptionManagerService,\n    element: Element,\n  ) {\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n    this.chartElement = element as HTMLElement;\n  }\n\n  protected attached(): void {\n    if(!this.columnsDomElement) return;\n    this.handleResize();\n    this.subscriptionManager.subscribeToElementResize(this.columnsDomElement, () => this.handleResize());\n  }\n\n  protected detached(): void {\n    this.subscriptionManager.disposeSubscriptions();\n  }\n\n  private handleResize(): void {\n    if(!this.columnsDomElement) return;\n    const maxScroll = this.columnsDomElement.scrollWidth - this.columnsDomElement.clientWidth;\n    this.columnsDomElement.scrollTo({ left: maxScroll });\n    this.showScrollOffset = this.columnsDomElement.scrollWidth > this.columnsDomElement.clientWidth;\n  }\n}","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/css-bar-chart/css-bar-chart'));\n}\n","import { autoinject, bindable, PLATFORM, TaskQueue, useView } from 'aurelia-framework';\nimport { FadeAnimationPlayer } from 'common/aurelia-classes/animationPlayer/FadeAnimationPlayer';\nimport { FullScreenContainer } from 'common/aurelia-components/full-screen-container/full-screen-container';\nimport { IIconConfig, IListStandardItem } from 'common/aurelia-components/list-standard/list-standard';\nimport { IconSize } from 'common/aurelia-components/x-icon/x-icon';\nimport { IQuizAnswerDto } from 'common/dto/course/quiz/quiz.answer.interface';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { DomUtils } from 'common/utils/DomUtils';\n\n/**\n * @event {CloseCustomSelectAnswerOverlayEvent} close-custom-select-answer-overlay\n */\n@autoinject\n@useView(PLATFORM.moduleName('./custom-select-answer-overlay.html'))\nexport class CustomSelectAnswerOverlay {\n  @bindable public answers!: IQuizAnswerDto;\n  @bindable public id!: number;\n  private element: HTMLElement;\n  private selectItems: IListStandardItem[] = [];\n  private selectedItem: number | null = null;\n  private taskQueue: TaskQueue;\n  private fullScreenContainer: FullScreenContainer | null = null;\n  private animationPlayer: FadeAnimationPlayer | null = null;\n  private contentWrapperElement: HTMLElement | null = null;\n  private contentElement: HTMLElement | null = null;\n\n  constructor(element: Element, taskQueue: TaskQueue) {\n    this.element = element as HTMLElement;\n    this.taskQueue = taskQueue;\n  }\n\n  protected attached(): void {\n    this.selectItems = [];\n    this.showOverlay();\n\n    for(let index = 0; index < 4; index++) {\n      const id = index + 1;\n      const answerKey = `text${id}` as keyof IQuizAnswerDto;\n      const item = {\n        graphic: this.createListItemGraphic(this.id === id),\n        icons: [],\n        click: {\n          callback: () => this.selectAnswer(index),\n        },\n        separatorAfter: true,\n        text: {\n          primary: `${this.answers[answerKey]}`,\n        },\n        multiline: true,\n      };\n      this.selectItems.push(item);\n    }\n  }\n\n  private showOverlay(): void {\n    this.taskQueue.queueMicroTask(() => {\n      assertNotNullOrUndefined(this.contentWrapperElement, 'can\\'t LockedAvatarComponentsDialog.open without a contentWrapperElement');\n      assertNotNullOrUndefined(this.contentElement, 'can\\'t LockedAvatarComponentsDialog.open without a contentElement');\n      this.animationPlayer = new FadeAnimationPlayer(this.contentWrapperElement, { duration: 200 });\n\n      // wait for the animationPlayer binding to propagate\n      this.taskQueue.queueMicroTask(() => {\n        this.getFullScreenContainer().show();\n      });\n    });\n  }\n\n  private selectAnswer(selectedItemIndex: number): void {\n    this.selectedItem = selectedItemIndex + 1;\n    for(const selectItem of this.selectItems) {\n      selectItem.graphic = this.createListItemGraphic(false);\n    }\n    this.selectItems[selectedItemIndex].graphic = this.createListItemGraphic(true);\n  }\n\n  private confirmAnswer(): void {\n    if(this.selectedItem) {\n      DomUtils.fireEvent(this.element, {\n        bubbles: true,\n        detail: {\n          selectedItem: this.selectedItem,\n        },\n        name: 'close-custom-select-answer-overlay',\n      });\n    }\n  }\n\n  private cancel(): void {\n    this.closeOverlay();\n  }\n\n  private closeOverlay(): void {\n    DomUtils.fireEvent(this.element, {\n      bubbles: true,\n      name: 'close-custom-select-answer-overlay',\n    });\n  }\n\n  private createListItemGraphic(selected: boolean): IIconConfig {\n    return {\n      name: `System/Radio/${selected ? 'Checked' : 'Unchecked'}`,\n      size: IconSize.normal,\n      type: 'custom',\n    };\n  }\n\n  private getFullScreenContainer(): FullScreenContainer {\n    assertNotNullOrUndefined(this.fullScreenContainer, 'fullScreenContainer not ref\\'d');\n    return this.fullScreenContainer;\n  }\n}\n\nexport type CloseCustomSelectAnswerOverlayEvent = Event & { detail: { selectedItem: number } | null };\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/custom-select-answer-overlay/custom-select-answer-overlay'));\n}\n","import { autoinject, bindable, computedFrom, PLATFORM, useView } from 'aurelia-framework';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { ILectureStatusDto } from 'common/dto/distinar/distinar.interface';\nimport { IEventDto } from 'common/dto/tenant/event/tenant.event.interface';\nimport { selectLocalAttendeeId, selectLocalHasTile } from 'common/store/selectors/conference.context.selectors';\nimport { ICommonState } from 'common/store/store.interface';\nimport * as ConferenceMutations from 'common/store/mutations/conference.context.mutations';\n\n/**\n * @slot the element to represent when `showVideo` is `true`\n */\n@autoinject()\n@useView(PLATFORM.moduleName('./distinar-conference-student-view.html'))\nexport class DistinarConferenceStudentView {\n  @bindable() public isMock = true;\n  @bindable() public activeLecture: IEventDto<string> | null = null;\n  @bindable() public tenantLogoPictureUrl: string | null = null;\n  @bindable() public lectureStatus: ILectureStatusDto | null = null;\n\n  private isAttached = false;\n\n  private localAttendeeId: string | null = null;\n  private isConferenceActive = false;\n\n  constructor(\n    private storeService: StoreService<ICommonState>,\n  ) { }\n\n  protected attached(): void {\n    this.isAttached = true;\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => !!state.distinar.lectureStatus?.conference.active,\n    ], (_state, conferenceActive) => {\n      this.isConferenceActive = conferenceActive;\n    });\n\n    if(!this.isMock) {\n      this.storeService.subscribeToDetailedChanges(this, [\n        state => selectLocalAttendeeId({ state }),\n        state => selectLocalHasTile({ state }),\n      ], (_state, attendeeId, hasTile) => {\n        this.localAttendeeId = hasTile ? attendeeId : null;\n      });\n    }\n  }\n\n  protected detached(): void {\n    this.isAttached = false;\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  @computedFrom('lectureStatus')\n  private get showVideo(): boolean {\n    return !!(this.lectureStatus?.conference.active && this.lectureStatus.conference.readyForStudentConnection);\n  }\n\n  @computedFrom()\n  private get statusInfo(): string | null {\n    if(this.lectureStatus?.conference.active && !this.lectureStatus.conference.readyForStudentConnection) {\n      return '[infoFirstLine]common.distinar-conference-student-view.notReadyForStudentConnection';\n    }\n\n    if(this.lectureStatus?.conference.active === false) {\n      return '[infoFirstLine]common.distinar-conference-student-view.notActive';\n    }\n\n    return null;\n  }\n\n  private async toggleHideMenus(): Promise<void> {\n    await this.storeService.dispatch(ConferenceMutations.updateHideMenus);\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/distinar-conference-student-view/distinar-conference-student-view'));\n}\n","import { autoinject, PLATFORM, useView } from 'aurelia-framework';\nimport { IPresentationBlockDto } from 'common/dto/course/content/block.interface';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { BlockUtils } from 'common/utils/BlockUtils';\nimport { CourseLectureBlockPicture } from '../course-lecture-block/course-lecture-block-picture/course-lecture-block-picture';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./distinar-course-picture-overlay.html'))\nexport class DistinarCoursePictureOverlay {\n  private static instance: DistinarCoursePictureOverlay | null = null;\n  private isOpen = false;\n  private block: IPresentationBlockDto | null = null;\n  private pictureRatio = CourseLectureBlockPicture.DEFAULT_RATIO;\n  private canZoomOut = false;\n  private onZoomOut: (() => void) | null = null;\n\n  public static open(pictureBlock: IPresentationBlockDto, options: IDistinarCoursePictureOverlayOptions): void {\n    assertNotNullOrUndefined(DistinarCoursePictureOverlay.instance, 'cannot open overlay without instance');\n    DistinarCoursePictureOverlay.instance.open(pictureBlock, options);\n  }\n\n  public static close(): void {\n    assertNotNullOrUndefined(DistinarCoursePictureOverlay.instance, 'cannot close overlay without instance');\n    DistinarCoursePictureOverlay.instance.close();\n  }\n\n  public static toggle(pictureBlock: IPresentationBlockDto, options: IDistinarCoursePictureOverlayOptions): void {\n    assertNotNullOrUndefined(DistinarCoursePictureOverlay.instance, 'cannot toggle overlay without instance');\n    DistinarCoursePictureOverlay.instance.toggle(pictureBlock, options);\n  }\n\n  protected attached(): void {\n    DistinarCoursePictureOverlay.instance = this;\n  }\n\n  protected detached(): void {\n    DistinarCoursePictureOverlay.instance = null;\n  }\n\n  private open(pictureBlock: IPresentationBlockDto, options: IDistinarCoursePictureOverlayOptions): void {\n    this.block = pictureBlock;\n    this.updatePictureRatio();\n    this.canZoomOut = options.canZoomOut;\n    this.onZoomOut = options.onZoomOut ?? null;\n    this.isOpen = true;\n  }\n\n  private close(): void {\n    this.block = null;\n    this.isOpen = false;\n    this.canZoomOut = false;\n    this.onZoomOut = null;\n    this.pictureRatio = CourseLectureBlockPicture.DEFAULT_RATIO;\n  }\n\n  private toggle(pictureBlock: IPresentationBlockDto, options: IDistinarCoursePictureOverlayOptions): void {\n    if(this.isOpen && this.block === pictureBlock) {\n      this.close();\n    } else {\n      this.open(pictureBlock, options);\n    }\n  }\n\n  private updatePictureRatio(): void {\n    assertNotNullOrUndefined(this.block, 'block cannot be null or undefined');\n\n    if(this.block.picture && this.block.picture.width && this.block.picture.height) {\n      this.pictureRatio = BlockUtils.getPictureBlockRatio(this.block.picture, this.block.pictureBlockRenderOptions);\n    } else {\n      this.pictureRatio = CourseLectureBlockPicture.DEFAULT_RATIO;\n    }\n  }\n\n  private handleZoomOut(): void {\n    if(this.canZoomOut) {\n      this.onZoomOut?.();\n      this.close();\n    }\n  }\n}\n\nexport interface IDistinarCoursePictureOverlayOptions {\n  canZoomOut: boolean;\n  onZoomOut?: () => void;\n}\n","import { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/distinar-course-picture-overlay/distinar-course-picture-overlay'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { SubscriptionManager, SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\n\nexport enum FloatingCorner {\n  BottomLeft = 'bottom-left',\n  BottomRight = 'bottom-right',\n  TopLeft = 'top-left',\n  TopRight = 'top-right',\n}\n\n/**\n * @slot - the `ConferenceVideo` element to be floated\n */\n@useView(PLATFORM.moduleName('./distinar-floating-video-container.html'))\n@autoinject()\nexport class DistinarFloatingVideoContainer {\n  @bindable() public floatingCorner: FloatingCorner = FloatingCorner.BottomRight;\n\n  private subscriptionManager: SubscriptionManager;\n  private domElement: HTMLElement;\n\n  private width: string | null = null;\n\n  constructor(\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n  ) {\n    this.domElement = element as HTMLElement;\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n  }\n\n  protected attached(): void {\n    this.subscriptionManager.subscribeToElementResize(this.domElement, () => {\n      this.width = `${this.domElement.getBoundingClientRect().width}px`;\n    });\n  }\n\n  protected detached(): void {\n    this.subscriptionManager.disposeSubscriptions();\n  }\n}\n","import { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/distinar-floating-video-container/distinar-floating-video-container'));\n}\n","import { autoinject, PLATFORM, useView } from 'aurelia-framework';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { ICommonState } from 'common/store/store.interface';\n\n@useView(PLATFORM.moduleName('./distinar-whiteboard-viewer.html'))\n@autoinject()\nexport class DistinarWhiteboardViewer {\n  private svgData: string | null = null;\n  private backgroundColor: string | null = null;\n  private showWhiteboard = false;\n\n  constructor(\n    private storeService: StoreService<ICommonState>,\n  ) { }\n\n  protected attached(): void {\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.distinar.lectureStatus?.whiteboard?.svgData ?? null,\n      state => state.distinar.lectureStatus?.whiteboard?.backgroundColor ?? null,\n    ], (_state, svgData, backgroundColor) => {\n      this.svgData = svgData;\n      this.backgroundColor = backgroundColor;\n      this.showWhiteboard = !!this.svgData || !!this.backgroundColor;\n    });\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/distinar-whiteboard-viewer/distinar-whiteboard-viewer'));\n}\n","import { autoinject, bindable, computedFrom, PLATFORM, useView } from 'aurelia-framework';\nimport { MathUtils } from 'common/utils/MathUtils';\nimport { IdGeneratorService } from '../../aurelia-services/IdGeneratorService';\n\nexport enum Color {\n  Primary = 'primary',\n  Secondary = 'secondary'\n}\n\n@useView(PLATFORM.moduleName('./donut-chart.html'))\n@autoinject()\nexport class DonutChart {\n  @bindable() public value = 0;\n  @bindable() public color: Color = Color.Primary;\n  @bindable() public fontScale = 1;\n  @bindable() public overrideMaxPercentage = false;\n  @bindable() public donutStrokeWidth = 35;\n  @bindable() public hidePercentage = false;\n  @bindable() public hideDisplay = false;\n  private donutDiameter = 230;\n  private donutInnerRadius = 0;\n  private donutCircumference = 0;\n  private circleFrontStrokeDash = 0;\n  private donutOuterRadius = 0;\n  private circleFrontStrokeDashOffset = 0;\n  private chartColorEnum = Color;\n  private idPrimary: number;\n  private idSecondary: number;\n\n  constructor(idGenerator: IdGeneratorService) {\n    this.idPrimary = idGenerator.getId();\n    this.idSecondary = idGenerator.getId();\n    this.initiateDonut();\n  }\n\n  public getCircleFrontStrokeDashOffset(value: number): number {\n    return this.donutCircumference * (1 - Math.min(value, 100) / 100);\n  }\n\n  @computedFrom('value')\n  private get isFull(): boolean {\n    return this.formatValue(this.value) === 100;\n  }\n\n  @computedFrom('value', 'overrideMaxPercentage', 'hideDisplay')\n  private get showValueText(): boolean {\n    return !this.hideDisplay && (this.overrideMaxPercentage || !this.isFull);\n  }\n\n  /**\n   * Calculates radius, dash, circumference etc from given diameter and strokewidth\n   * to make it responsive, change diameter and strokewidth\n   */\n  private initiateDonut(): void {\n    this.donutInnerRadius = (this.donutDiameter - this.donutStrokeWidth) / 2;\n    this.donutCircumference = Math.ceil(2 * this.donutInnerRadius * Math.PI);\n    this.donutOuterRadius = this.donutDiameter / 2;\n    this.circleFrontStrokeDash = Math.ceil(this.donutInnerRadius * 2 * Math.PI);\n    this.circleFrontStrokeDashOffset = this.circleFrontStrokeDash;\n  }\n\n  private formatValue(value: number): number {\n    return MathUtils.roundProgress(value, this.overrideMaxPercentage);\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/donut-chart/donut-chart'));\n}\n","/**\n * Adapted from recordIT\n */\n\n/* eslint-disable no-underscore-dangle */\nimport { inject, bindable, useView, PLATFORM } from 'aurelia-framework';\nimport { DomEventHelper } from './util/DomEventHelper';\nimport { ImageHelper } from './util/ImageHelper';\nimport { Tool } from './tools/Tool';\nimport './msvg/msvg';\n\n/**\n * depends on the msvg library\n *\n * this is the basis for the provided tools, but the tool selection/activation has to be controlled externally\n *\n * @event changed - fired when the content of the svg element has changed, e.g. from a tool\n */\n@inject(Element)\n@useView(PLATFORM.moduleName('./drawing-area.html'))\nexport class DrawingArea {\n\n  /**\n   * height of the resulting picture\n   *\n   * @type {number}\n   */\n  @bindable height = 300;\n\n  /**\n   * width of the resulting image\n   *\n   * @type {number}\n   */\n  @bindable width = 400;\n\n  /**\n   * the attributes which should be removed from the base64 export\n   *\n   * @type {Array<string>}\n   * @private\n   */\n  _svgBindingAttributes = [\n    'au-target-id', 'ref', 'class', 'click.trigger', 'mousemove.trigger',\n    'mouseenter.trigger', 'mouseleave.trigger', 'mousedown.trigger',\n    'mouseup.trigger', 'touchstart.trigger', 'touchmove.trigger', 'touchend.trigger',\n  ];\n\n  _domElement: HTMLElement;\n  _svgElement: SVGSVGElement | null = null;\n  _msvg: Msvg.Msvg | null = null;\n  _activeTool: Tool | null = null;\n  _ratio = 1;\n\n  constructor(element: HTMLElement) {\n    this._domElement = element;\n  }\n\n  public bind(): void {\n    this._msvg = new Msvg.Msvg(this._getSvgElement());\n    this._updateViewBox();\n    this._updateRatio();\n  }\n\n  private _reset(): void {\n    this.empty();\n    this.modified();\n  }\n\n  /**\n   * @returns {Msvg.Msvg}\n   */\n  public getMsvg(): Msvg.Msvg {\n    if(!this._msvg) {\n      throw new Error('Msvg is not available!');\n    }\n    return this._msvg;\n  }\n\n  /**\n   * if you modify the drawing area msvg, call this function so other usages can be informed about the modification\n   */\n  public modified(): void {\n    DomEventHelper.fireEvent(this._domElement, {\n      name: 'changed',\n      detail: null,\n    });\n  }\n\n  /**\n   * set the active tool to delegate the events to\n   *\n   * @param {Tool|null} tool\n   */\n  public setActiveTool(tool: Tool | null): void {\n    this._activeTool = tool;\n  }\n\n  public empty(): void {\n    if(this._msvg) {\n      this._msvg.empty();\n    }\n  }\n\n  protected heightChanged(): void {\n    this._updateViewBox();\n    this._updateRatio();\n  }\n\n  protected widthChanged(): void {\n    this._updateViewBox();\n    this._updateRatio();\n  }\n\n  /**\n   * toBeDrawnOnCanvas:\n   *  adds the height and width attribute so firefox actually will draw it on a canvas (https://bugzilla.mozilla.org/show_bug.cgi?id=700533)\n   *  use this only for drawing it on the canvas and not for saving it!!\n   *\n   * @param {boolean} [toBeDrawnOnCanvas]\n   * @returns {string}\n   */\n  public exportSvgAsDataUrl(toBeDrawnOnCanvas = false): string {\n    return ImageHelper.svgElementToDataUrl(\n      this._getSvgElementToExport(toBeDrawnOnCanvas),\n    );\n  }\n\n  private _getSvgElement(): SVGSVGElement {\n    if(!this._svgElement) {\n      throw new Error('SVG element not available!');\n    }\n    return this._svgElement;\n  }\n\n  private _updateViewBox(): void {\n    if(this._msvg) {\n      this._msvg.setViewBoxWithPoints(\n        new Msvg.Point(0, 0),\n        new Msvg.Point(this.width, this.height),\n      );\n    }\n  }\n\n  private _updateRatio(): void {\n    this._ratio = this.width / this.height;\n  }\n\n  private _getContentWrapperStyle(ratio: number): any {\n    return {\n      'padding-bottom': `${(1 / ratio) * 100}%`,\n    };\n  }\n\n  /**\n   * toBeDrawnOnCanvas:\n   *  adds the height and width attribute so firefox actually will draw it on a canvas (https://bugzilla.mozilla.org/show_bug.cgi?id=700533)\n   *  use this only for drawing it on the canvas and not for saving it!!\n   *\n   * @param {boolean} [toBeDrawnOnCanvas]\n   * @returns {SVGSVGElement}\n   * @private\n   */\n  private _getSvgElementToExport(toBeDrawnOnCanvas = false): SVGSVGElement {\n    const svg: SVGSVGElement = (this._getSvgElement().cloneNode(true)) as SVGSVGElement;\n    this._svgBindingAttributes.forEach(attr => {\n      svg.removeAttribute(attr);\n    });\n\n    if(toBeDrawnOnCanvas) {\n      svg.setAttribute('width', `${svg.viewBox.baseVal.width}px`);\n      svg.setAttribute('height', `${svg.viewBox.baseVal.height}px`); // needed for firefox https://bugzilla.mozilla.org/show_bug.cgi?id=700533\n    }\n\n    svg.setAttribute('xmlns', Msvg.Utils.Definitions.svgNamespace);\n    svg.setAttribute('xmlns:xlink', Msvg.Utils.Definitions.xlinkNamespace);\n    return svg;\n  }\n\n  // ************ Event Handler **************\n\n  private _handleDrawingAreaClick(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.mouseClicked(event);\n    return true;\n  }\n\n  private _handleDrawingAreaMousemove(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.mouseMoved(event);\n    return true;\n  }\n\n  private _handleDrawingAreaMouseenter(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.mouseEntered(event);\n    return true;\n  }\n\n  private _handleDrawingAreaMouseleave(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.mouseLeft(event);\n    return true;\n  }\n\n  private _handleDrawingAreaMousedown(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.mouseDown(event);\n    return true;\n  }\n\n  private _handleDrawingAreaMouseup(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.mouseUp(event);\n    return true;\n  }\n\n  private _handleDrawingAreaTouchstart(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.touchStarted(event);\n    return true;\n  }\n\n  private _handleDrawingAreaTouchmove(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.touchMoved(event);\n    return !this._activeTool; // only prevent the touchmove if there is an active tool\n  }\n\n  private _handleDrawingAreaTouchend(event: MouseEvent): boolean {\n    this._activeTool?.eventDelegator.touchEnded(event);\n    return true;\n  }\n\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/drawing-area/drawing-area'));\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\n\nimport { Tool } from './Tool';\n\nexport class ArrowTool extends Tool {\n  _name = 'Pfeil';\n  _icons = ['fal fa-arrow-up'];\n  _machineName = 'arrow';\n\n  _firstPosition: Msvg.Point | null = null;\n  _lastSecondPosition: Msvg.Point | null = null;\n  _path: Msvg.Path|null = null;\n\n  protected _cancel(): void {\n    if(this._path) {\n      this._msvg?.remove(this._path);\n    }\n    super._cancel();\n  }\n\n  protected _reset(): void {\n    super._reset();\n    this._firstPosition = null;\n    this._lastSecondPosition = null;\n    this._path = null;\n  }\n\n  protected _mouseClickedHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(this._path) {\n      this._modified();\n      this._reset();\n    } else {\n      this._startNewPath(position);\n    }\n  }\n\n  protected _mouseMovedHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(this._path) {\n      this._updatePath(position);\n    }\n  }\n\n  protected _draggingHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(!this._dragStartPosition) return;\n    if(!this._path) {\n      this._startNewPath(this._dragStartPosition);\n    }\n\n    this._updatePath(position);\n  }\n\n  protected _draggingEndedHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(!this._msvg || !this._path) return;\n    this._updatePath(position);\n    this._msvg.append(this._path);\n    this._modified();\n    this._reset();\n  }\n\n  protected _startNewPath(position: Msvg.Point): void {\n    this._firstPosition = position;\n    this._path = this._createPath();\n    this._msvg?.append(this._path);\n  }\n\n  protected _createPath(): Msvg.Path {\n    this._lastSecondPosition = null;\n    return (new Msvg.Path())\n      .setStroke(this._color)\n      .setStrokeWidth(this._size)\n      .setStrokeLinejoin('round')\n      .setFill('none');\n  }\n\n  protected _stylingChanged(): void {\n    if(this._path) {\n      this._path\n        .setStroke(this._color)\n        .setStrokeWidth(this._size);\n\n      // since the length of the legs also depend on the size, we have to update the path itself too\n      if(this._lastSecondPosition) {\n        this._updatePath(this._lastSecondPosition);\n      }\n    }\n  }\n\n  /**\n   *\n   * @param {Msvg.Point} secondPosition\n   * @private\n   */\n  protected _updatePath(secondPosition: Msvg.Point): void {\n    if(!this._firstPosition || !this._path) return;\n    const pos1 = this._firstPosition;\n    const pos2 = secondPosition;\n\n    const arrowLength = Math.sqrt((pos2.x - pos1.x) ** 2 + (pos2.y - pos1.y) ** 2);\n\n    const angle = 25;\n    const angleRad = (2 * Math.PI * angle) / 360;\n\n    const arrowLegLengthFactor = 8;\n    const arrowLegLength = this._size * arrowLegLengthFactor;\n\n    const pos3 = new Msvg.Point(\n      pos2.x + arrowLegLength / arrowLength * ((pos1.x - pos2.x) * Math.cos(angleRad) + (pos1.y - pos2.y) * Math.sin(angleRad)),\n      pos2.y + arrowLegLength / arrowLength * ((pos1.y - pos2.y) * Math.cos(angleRad) - (pos1.x - pos2.x) * Math.sin(angleRad)),\n    );\n    const pos4 = new Msvg.Point(\n      pos2.x + arrowLegLength / arrowLength * ((pos1.x - pos2.x) * Math.cos(angleRad) - (pos1.y - pos2.y) * Math.sin(angleRad)),\n      pos2.y + arrowLegLength / arrowLength * ((pos1.y - pos2.y) * Math.cos(angleRad) + (pos1.x - pos2.x) * Math.sin(angleRad)),\n    );\n\n    this._path\n      .reset()\n      .addMoveToAbsolute(pos1)\n      .addLineToAbsolute(pos2)\n      .addLineToAbsolute(pos3)\n      .addMoveToAbsolute(pos2)\n      .addLineToAbsolute(pos4);\n\n    this._lastSecondPosition = secondPosition;\n  }\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { Tool } from './Tool';\nimport { PointerEventHelper } from '../util/PointerEventHelper';\n\nexport class DeleteTool extends Tool {\n  _name = 'Löschen';\n  _icons = ['far fa-trash', 'fas fa-mouse-pointer'];\n  _machineName = 'delete';\n  _mouseIsDown = false;\n  /** @type {Map} */\n  _originalElementToClickAreaElementMap = new Map();\n  /** @type {Map} */\n  _clickAreaElementToOriginalElementMap = new Map();\n\n  drawingAreaExternallyModified() {\n    super.drawingAreaExternallyModified();\n\n    this._removeClickAreaElements();\n    this._addClickAreaElements();\n  }\n\n  _activated() {\n    this._addClickAreaElements();\n  }\n\n  _cancel() {\n    super._cancel();\n    this._removeClickAreaElements();\n  }\n\n  /**\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  _mouseClickedHandler(event, position) {\n    const rootElement = this._getRootSvgElement(event.target);\n    const originalElement = this._clickAreaElementToOriginalElementMap.get(rootElement);\n    const element = originalElement ? originalElement : rootElement;\n    if(element && this._elementIsDeletable(element)) {\n      this._removeRootElementFromMsvg(element);\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   *\n   * @param {Element} element\n   * @returns {(SVGElement|null)}\n   * @private\n   */\n  _getRootSvgElement(element) {\n    let svgElement = this._msvg.getElement();\n    let currentElement = element;\n\n    do {\n      if(currentElement.parentNode && currentElement.parentNode === svgElement) {\n        return currentElement;\n      }\n    } while(currentElement = currentElement.parentNode);\n\n    return null;\n  }\n\n  /**\n   *\n   * @param {Element} element\n   * @private\n   */\n  _elementIsDeletable(element) {\n    return !element.hasAttribute('data-old-sketch');\n  }\n\n  /**\n   *\n   * @param {SVGElement} rootElement\n   * @private\n   */\n  _removeRootElementFromMsvg(rootElement) {\n    this._msvg.removeSvgElement(rootElement);\n    this._removeClickAreaElements();\n    this._modified();\n    this._addClickAreaElements();\n  }\n\n  /**\n   *\n   * @param {MouseEvent} event\n   * @returns {Msvg.Point}\n   * @private\n   */\n  _getMousePositionRelativeToSvgElement(event) {\n    const position = PointerEventHelper.getClientPositionFromEvent(event);\n    const boundingRect = this._msvg.getElement().getBoundingClientRect();\n    return new Msvg.Point(\n      position.getX() - boundingRect.x,\n      position.getY() - boundingRect.y\n    );\n  }\n\n  _addClickAreaElements() {\n    const svgElement = this._msvg.getElement();\n    const childNodes = Array.from(svgElement.childNodes);\n    const insertRefNode = svgElement.firstChild;\n\n    for(let key = childNodes.length - 1; key >= 0; key--) {\n      const node = childNodes[key];\n      if(!(node instanceof SVGPathElement || node instanceof SVGRectElement || node instanceof SVGLineElement)) {\n        continue;\n      }\n\n      if(this._originalElementToClickAreaElementMap.get(node)) {\n        continue;\n      }\n\n      const clone = node.cloneNode(true);\n      this._originalElementToClickAreaElementMap.set(node, clone);\n      this._clickAreaElementToOriginalElementMap.set(clone, node);\n\n      clone.setAttribute('stroke', 'transparent');\n      clone.setAttribute('stroke-width', 25);\n      clone.setAttribute('stroke-linecap', 'round');\n      clone.setAttribute('data-temporary-element', ''); //just in case this lands in the result, to be able to remove it later on\n      svgElement.insertBefore(clone, insertRefNode);\n    }\n  }\n\n  _removeClickAreaElements() {\n    const clones = this._clickAreaElementToOriginalElementMap.keys();\n    for(let clone of clones) {\n      if(clone.parentNode) {\n        clone.parentNode.removeChild(clone);\n      }\n    }\n\n    this._clickAreaElementToOriginalElementMap = new Map();\n    this._originalElementToClickAreaElementMap = new Map();\n  }\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { Tool } from './Tool';\n\nexport class EllipseTool extends Tool {\n\n  _name = 'Ellipse';\n  _icons = ['far fa-circle'];\n  _machineName = 'ellipse';\n  _instantDragging = true;\n\n  _firstPosition: Msvg.Point | null = null;\n  _path: Msvg.Path | null = null;\n\n  _cancel() {\n    if(this._path) {\n      this._msvg.remove(this._path);\n    }\n    super._cancel();\n  }\n\n  _reset() {\n    super._reset();\n    this._firstPosition = null;\n    this._path = null;\n  }\n\n  /**\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  _mouseClickedHandler(event, position) {\n    if(this._path) {\n      this._updatePath(position);\n      this._modified();\n      this._reset();\n    } else {\n      this._startNewPath(position);\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  _mouseMovedHandler(event, position) {\n    if(this._path) {\n      this._updatePath(position);\n    }\n  }\n\n  /**\n   * @param event\n   * @param {Msvg.Point} position\n   * @private\n   */\n  _draggingHandler(event, position) {\n    if(!this._path) {\n      this._startNewPath(position);\n    }\n\n    this._updatePath(position);\n  }\n\n  /**\n   * @param event\n   * @param {Msvg.Point} position\n   * @private\n   */\n  _draggingEndedHandler(event, position) {\n    this._updatePath(position);\n    this._msvg.append(this._path);\n    this._modified();\n    this._reset();\n  }\n\n  /**\n   * @param {Msvg.Point} position\n   * @private\n   */\n  _startNewPath(position) {\n    this._path = this._createPath();\n    this._msvg.append(this._path);\n    this._firstPosition = position;\n  }\n\n  /**\n   * @returns {Msvg.Path}\n   * @private\n   */\n  _createPath() {\n    const path = new Msvg.Path();\n    this._setPathStyling(path);\n    return path;\n  }\n\n  _stylingChanged() {\n    if(this._path) {\n      this._setPathStyling(this._path);\n    }\n  }\n\n  /**\n   * @param {Msvg.Path} path\n   * @private\n   */\n  _setPathStyling(path) {\n    path.setStrokeWidth(this._size)\n      .setStroke(this._color)\n      .setAttribute('stroke-dasharray', this._getStrokeDashArrayStyleString())\n      .setFill('none');\n  }\n\n  /**\n   * @param {Msvg.Point} secondPosition\n   * @private\n   */\n  protected _updatePath(secondPosition: Msvg.Point): void {\n    if(!this._firstPosition || !this._path) return;\n    const pos1 = this._firstPosition;\n    const pos2 = secondPosition;\n\n    const x = Math.min(pos1.x, pos2.x);\n    const y = Math.min(pos1.y, pos2.y);\n    const w = Math.abs(pos1.x - pos2.x);\n    const h = Math.abs(pos1.y - pos2.y);\n    const kappa = 0.5522848;\n    const ox = (w / 2) * kappa;\n    const oy = (h / 2) * kappa;\n    const xm = x + w / 2;\n    const ym = y + h / 2;\n    const xe = x + w;\n    const ye = y + h;\n\n    this._path\n      .reset()\n      .addMoveToAbsolute(new Msvg.Point(x, ym))\n      .addCurveToAbsolute(new Msvg.Point(xm, y), new Msvg.Point(x, ym - oy), new Msvg.Point(xm - ox, y))\n      .addCurveToAbsolute(new Msvg.Point(xe, ym), new Msvg.Point(xm + ox, y), new Msvg.Point(xe, ym - oy))\n      .addCurveToAbsolute(new Msvg.Point(xm, ye), new Msvg.Point(xe, ym + oy), new Msvg.Point(xm + ox, ye))\n      .addCurveToAbsolute(new Msvg.Point(x, ym), new Msvg.Point(xm - ox, ye), new Msvg.Point(x, ym + oy))\n      .addClosePath();\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n/* global Msvg */\n\nimport { Tool } from './Tool';\n\nexport class FreehandTool extends Tool {\n\n  _name = 'Freihand';\n  _icons = ['far fa-paint-brush'];\n  _machineName = 'freehand';\n  _instantDragging = true;\n  _gridIsEnabled = false;\n\n  /**\n   * @type {Array<Msvg.Path>}\n   * @private\n   */\n  _paths: Array<Msvg.Path> = [];\n\n  protected _cancel(): void {\n    this._paths.forEach(path => {\n      this._msvg?.remove(path);\n    });\n    super._cancel();\n  }\n\n  protected _reset(): void {\n    super._reset();\n    this._paths = [];\n  }\n\n  /**\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _draggingHandler(event: Event, position: Msvg.Point): void {\n    if(this._lastDraggingPosition) {\n\n      let path = this._paths[this._paths.length - 1];\n      if(!path) {\n        path = this._startNewPath(this._lastDraggingPosition);\n      }\n\n      path.addLineToAbsolute(position);\n    }\n  }\n\n  /**\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _draggingEndedHandler(event: Event, position: Msvg.Point): void {\n    this._paths.forEach(path => {\n      this._msvg?.append(path);\n    });\n    this._modified();\n    this._reset();\n  }\n\n  // ********** we want to pause drawing the line when we are leaving the drawing area and continue again when we enter\n\n  protected _mouseLeftHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(this._isDragging) {\n      this._draggingHandler(event, position);\n    }\n  }\n\n  protected _mouseEnteredHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(this._isDragging) {\n      this._startNewPath(position);\n    }\n  }\n\n  /**\n   * @param {Msvg.Point} startPosition\n   * @returns {Msvg.Path}\n   * @private\n   */\n  protected _startNewPath(startPosition: Msvg.Point): Msvg.Path {\n    const path = new Msvg.Path();\n    path.addMoveToAbsolute(startPosition);\n    path.setFill('none')\n      .setStroke(this._color)\n      .setAttribute('stroke-dasharray', this._getStrokeDashArrayStyleString())\n      .setStrokeWidth(this._size)\n      .setStrokeLinejoin('round')\n      .setAttribute('stroke-linecap', 'round');\n\n    this._msvg?.append(path);\n    this._paths.push(path);\n    return path;\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { Tool } from './Tool';\n\nexport class LineTool extends Tool {\n\n  _name = 'Linie';\n  _icons = ['far fa-window-minimize', 'far fa-pen'];\n  _machineName = 'line';\n\n  /** @type {Msvg.Line|null} */\n  _line = null;\n\n  _cancel() {\n    if(this._line) {\n      this._msvg.remove(this._line);\n    }\n    super._cancel();\n  }\n\n  _reset() {\n    super._reset();\n    this._line = null;\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  _mouseClickedHandler(event, position) {\n    if(this._line) {\n      this._modified();\n      this._reset();\n    } else {\n      this._startNewLine(position);\n    }\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  _mouseMovedHandler(event, position) {\n    if(this._line) {\n      this._line.setPosition2(position);\n    }\n  }\n\n  /**\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  _draggingHandler(event, position) {\n    if(!this._line) {\n      this._startNewLine(this._dragStartPosition);\n    }\n\n    this._line.setPosition2(position);\n  }\n\n  /**\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  _draggingEndedHandler(event, position) {\n    this._line.setPosition2(position);\n    this._msvg.append(this._line);\n\n    this._modified();\n    this._reset();\n  }\n\n  /**\n   *\n   * @param {Msvg.Point} position\n   * @private\n   */\n  _startNewLine(position) {\n    this._line = this._createLine(position);\n    this._msvg.append(this._line);\n  }\n\n  /**\n   *\n   * @param {Msvg.Point} startPosition\n   * @returns {Msvg.Line}\n   * @private\n   */\n  _createLine(startPosition) {\n    return (new Msvg.Line())\n      .setStroke(this._color)\n      .setAttribute('stroke-dasharray', this._getStrokeDashArrayStyleString())\n      .setStrokeWidth(this._size)\n      .setPosition1(startPosition)\n      .setPosition2(startPosition);\n  }\n\n  _stylingChanged() {\n    if(this._line) {\n      this._line\n        .setStroke(this._color)\n        .setAttribute('stroke-dasharray', this._getStrokeDashArrayStyleString())\n        .setStrokeWidth(this._size);\n    }\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { Tool } from './Tool';\n\nexport class RectangleTool extends Tool {\n\n  _name = 'Rechteck';\n  _icons = ['far fa-square'];\n  _machineName = 'rectangle';\n\n  _rectangle: Msvg.Rectangle | null = null;\n\n  _firstPosition: Msvg.Point | null = null;\n\n  protected _cancel(): void {\n    if(this._rectangle) {\n      this._msvg?.remove(this._rectangle);\n    }\n    super._cancel();\n  }\n\n  protected _reset(): void {\n    super._reset();\n    this._firstPosition = null;\n    this._rectangle = null;\n  }\n\n  protected _mouseClickedHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(this._rectangle) {\n      this._updateRectanglePosition(position);\n      this._msvg?.append(this._rectangle);\n      this._modified();\n      this._reset();\n    } else {\n      this._startNewRectangle(position);\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _mouseMovedHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(this._rectangle) {\n      this._updateRectanglePosition(position);\n    }\n  }\n\n  /**\n   * @param event\n   * @param {Msvg.Point} position\n   * @private\n   */\n  protected _draggingHandler(event: MouseEvent, position: Msvg.Point): void {\n    if(!this._rectangle) {\n      this._startNewRectangle(this._dragStartPosition);\n    }\n    this._updateRectanglePosition(position);\n  }\n\n  /**\n   * @param event\n   * @param {Msvg.Point} position\n   * @private\n   */\n  protected _draggingEndedHandler(event: MouseEvent, position: Msvg.Point): void {\n    this._updateRectanglePosition(position);\n    this._msvg?.append(this._rectangle);\n    this._modified();\n    this._reset();\n  }\n\n  protected _startNewRectangle(position: Msvg.Point): void {\n    this._firstPosition = position;\n    this._rectangle = this._createRectangle(position);\n    this._msvg?.append(this._rectangle);\n  }\n\n  protected _createRectangle(position: Msvg.Point): Msvg.Rectangle {\n    return (new Msvg.Rectangle())\n      .setRx(position.x)\n      .setRy(position.y)\n      .setHeight(0)\n      .setWidth(0)\n      .setRy(0)\n      .setRx(0)\n      .setFill('none')\n      .setStroke(this._color)\n      .setAttribute('stroke-dasharray', this._getStrokeDashArrayStyleString())\n      .setStrokeWidth(this._size);\n  }\n\n  private _updateRectanglePosition(secondPosition: Msvg.Point): void {\n    const bounds = new Msvg.Utils.Bounds([this._firstPosition, secondPosition]);\n    const size = bounds.getSize();\n    this._rectangle\n      .setPosition(bounds.getTopLeftCorner())\n      .setWidth(size.x)\n      .setHeight(size.y);\n  }\n\n  protected _stylingChanged(): void {\n    if(this._rectangle) {\n      this._rectangle\n        .setStroke(this._color)\n        .setAttribute('stroke-dasharray', this._getStrokeDashArrayStyleString())\n        .setStrokeWidth(this._size);\n    }\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\n/* global Msvg */\n\nimport { IScale, TransformHelper } from '../util/Geometry/TransformHelper';\nimport { Utils } from '../util/Utils';\n\n/**\n * this class converts points into svg coordinates\n */\nexport class SvgPointerEventNormalizer {\n\n  public static normalizeMouseEvent(event: MouseEvent, msvg: Msvg.Msvg): Msvg.Point {\n    const element = msvg.getElement();\n    const boundingClientRect = element.getBoundingClientRect();\n\n    const unscaledOffsetX = event.clientX - boundingClientRect.left;\n    const unscaledOffsetY = event.clientY - boundingClientRect.top;\n\n    const elementScale = this._getScaleOfElement(element);\n\n    const scaledOffsetX = unscaledOffsetX / elementScale.scaleX;\n    const scaledOffsetY = unscaledOffsetY / elementScale.scaleY;\n\n    return this.normalizeOffsetCoordinates(new Msvg.Point(scaledOffsetX, scaledOffsetY), msvg);\n  }\n\n  public static normalizeTouchEvent(event: TouchEvent, msvg: Msvg.Msvg): Msvg.Point {\n    const touch = event.targetTouches[0];\n\n    const element = msvg.getElement();\n    const boundingClientRect = element.getBoundingClientRect();\n\n    const x = touch ? touch.clientX - boundingClientRect.left : 0;\n    const y = touch ? touch.clientY - boundingClientRect.top : 0;\n\n    const elementScale = this._getScaleOfElement(element);\n\n    const scaledX = x / elementScale.scaleX;\n    const scaledY = y / elementScale.scaleY;\n\n    return this.normalizeOffsetCoordinates(new Msvg.Point(scaledX, scaledY), msvg);\n  }\n\n  /**\n   * this is basically the reverse function for normalizeOffsetCoordinates\n   * result is relative to the top left border of the svg element\n   */\n  public static getOffsetCoordinatesForSvgPosition(position: Msvg.Point, msvg: Msvg.Msvg): Msvg.Point {\n    const computed = window.getComputedStyle(msvg.getElement());\n    const viewBox = msvg.getViewBox();\n\n    const widthRatio = parseFloat(computed.width) / viewBox.width;\n    const heightRatio = parseFloat(computed.height) / viewBox.height;\n\n    return new Msvg.Point(\n      (position.x - viewBox.x) * widthRatio,\n      (position.y - viewBox.y) * heightRatio,\n    );\n  }\n\n  /**\n   * coord must be relative to the top left of the msvg itself!\n   */\n  public static normalizeOffsetCoordinates(coord: Msvg.Point, msvg: Msvg.Msvg): Msvg.Point {\n    const computed = window.getComputedStyle(msvg.getElement());\n    const viewBox = msvg.getViewBox();\n\n    const widthRatio = viewBox.width / parseFloat(computed.width);\n    const heightRatio = viewBox.height / parseFloat(computed.height);\n\n    return new Msvg.Point(\n      coord.x * widthRatio + viewBox.x,\n      coord.y * heightRatio + viewBox.y,\n    );\n  }\n\n  public static _getScaleOfElement(element: Element): IScale {\n    let scaleX = 1;\n    let scaleY = 1;\n\n    Utils.walkThroughParentElements(element.parentElement, elem => {\n      const computedStyle = window.getComputedStyle(elem);\n      const elementScale = TransformHelper.getScaleFromTransformMatrix(computedStyle.transform);\n\n      if(elementScale) {\n        scaleX *= elementScale.scaleX;\n        scaleY *= elementScale.scaleY;\n      }\n\n      return true;\n    });\n\n    return {\n      scaleX,\n      scaleY,\n    };\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\n/* global Msvg */\n\nimport { DrawingArea } from '../drawing-area';\nimport { ToolEventDelegator } from './ToolEventDelegator';\nimport { ToolGrid } from './ToolGrid';\n\n/**\n * you shouldn't need to override public functions in the Tool implementations\n *\n * A Tool has to call the _modified function everytime it finished drawing a shape (e.g. a line for the LineTool)!\n *\n * if you externally modify the drawingArea while the tool is active, call the drawingAreaExternallyModified function\n */\nexport class Tool {\n\n  // ***** these should be overriden!\n  _name = 'NoName';\n  _icons: Array<string> = [];\n  _machineName = 'tool';\n\n  /**\n   * if this is true then there will be no min distance for dragging (useful for tools which have no click handling)\n   */\n  _instantDragging = false;\n\n  /**\n   * set this to false to disable the grid for this tool\n   * you probably need to disable the grid if you have _instantDragging on true\n   */\n  _gridIsEnabled = true;\n\n  // ***** you shouldn't need to override this\n  _active = false;\n  _drawingArea: DrawingArea|null = null;\n  protected _msvg: Msvg.Msvg | null = null;\n\n  /* should be used for line thickness etc */\n  _size = 5;\n  _color = '#fff';\n  _strokeDashArray = [0];\n\n  // ***** Dragging handling properties\n  /**\n   * only use this value if _isDragging is true\n   */\n  _dragStartPosition: Msvg.Point|null = null;\n\n  /**\n   * to store the last position while dragging since the touchEnd Event doesn't deliver any coordinates anymore\n   */\n  _lastDraggingPosition: Msvg.Point | null = null;\n  _isDragging = false;\n\n  _grid: ToolGrid | null = null;\n\n  /**\n   * forward all events into this eventDelegator\n   */\n  eventDelegator: ToolEventDelegator;\n\n  constructor() {\n    this.eventDelegator = new ToolEventDelegator(this);\n  }\n\n  /**\n   * call this to start the tool\n   *\n   * @param {DrawingArea} drawingArea\n   * @param {ToolGrid|null} [grid]\n   */\n  public activate(drawingArea: DrawingArea, grid: ToolGrid|null): void {\n    this._active = true;\n\n    this._drawingArea = drawingArea;\n    this._msvg = drawingArea.getMsvg();\n\n    this._grid = grid || new ToolGrid(new Msvg.Msvg());\n    this._grid.setEnabled(this._gridIsEnabled);\n\n    drawingArea.setActiveTool(this);\n\n    this._reset();\n    this._activated();\n  }\n\n  /**\n   * call this to stop using the tool (some tools will cancel some if it effects)\n   */\n  public finish(): void {\n    this._active = false;\n    this._drawingArea?.setActiveTool(null);\n\n    this._cancel();\n\n    this._msvg = null;\n    this._drawingArea = null;\n    this._finished();\n  }\n\n  /**\n   * cancel the tool progress\n   * e.g. for tools with preview (Ellipse ...) you will need to click once for the first point, and a second time for the second point.\n   * to cancel the tool and start from new you need to call this method\n   */\n  public cancel(): void {\n    this._cancel();\n  }\n\n  // ********** Event notify functions\n\n  /**\n   * get the tools name (meant for display to the user)\n   *\n   * @returns {string}\n   */\n  public getName(): string {\n    return this._name;\n  }\n\n  /**\n   * an array of classnames\n   *\n   * @returns {string[]}\n   */\n  public getIcons(): Array<string> {\n    return this._icons;\n  }\n\n  /**\n   * name to reference the tool over css or something\n   *\n   * @returns {string}\n   */\n  public getMachineName(): string {\n    return this._machineName;\n  }\n\n  /**\n   * @return {boolean}\n   */\n  public isActive(): boolean {\n    return this._active;\n  }\n\n  /**\n   * @return {Msvg.Msvg}\n   */\n  public getMsvg(): Msvg.Msvg | null {\n    return this._msvg;\n  }\n\n  /**\n   * @param {number} size\n   */\n  public setSize(size: number): void {\n    this._size = size;\n    this._stylingChanged();\n  }\n\n  public setColor(color: string): void {\n    this._color = color;\n    this._stylingChanged();\n  }\n\n  public setStrokeDashArray(strokeDashArray: Array<number>): void {\n    this._strokeDashArray = strokeDashArray;\n    this._stylingChanged();\n  }\n\n  /**\n   * @returns {string}\n   */\n  public _getStrokeDashArrayStyleString(): string {\n    return this._strokeDashArray.map(n => n * this._size).join(',');\n  }\n\n  /**\n   * call this function everytime the drawing area has been externally modified while this tool is active\n   */\n  public drawingAreaExternallyModified(): void {\n    //\n  }\n\n  /**\n   * return true if the tool doesn't have a min dragging distance\n   *\n   * @return {boolean}\n   */\n  public instantDraggingActivated(): boolean {\n    return this._instantDragging;\n  }\n\n  // ********** internal functions\n\n  /**\n   * remove all of your pending elements in here and reset the element\n   *\n   * @protected\n   */\n  protected _cancel(): void {\n    this._reset();\n  }\n\n  /**\n   * reset the current action\n   */\n  protected _reset(): void {\n    this.eventDelegator.reset();\n    this._dragStartPosition = null;\n    this._isDragging = false;\n    this._lastDraggingPosition = null;\n    this._grid?.setHighlightedPoint(null);\n  }\n\n  protected _modified(): void {\n    this._drawingArea?.modified();\n  }\n\n  /**\n   * override this if you need this\n   *\n   * this gets called at the end of activate\n   * @protected\n   */\n  protected _activated(): void {\n\n  }\n\n  /**\n   * overrided this if you need this\n   *\n   * this gets called at the end of finish\n   * @protected\n   */\n  protected _finished(): void {\n\n  }\n\n  /**\n   * gets called after size/color or whatever additional stylings have been changed\n   * overwrite this so you can update the preview correctly\n   *\n   * @protected\n   */\n  protected _stylingChanged(): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _mouseMovedHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _mouseClickedHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _mouseEnteredHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {MouseEvent} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _mouseLeftHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _touchStartedHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _touchMovedHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _touchEndedHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * gets called everytime the user made a dragging action\n   *\n   * you are probably interested in _dragStartPosition too\n   *\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _draggingHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n  /**\n   * the position is already normalized\n   *\n   * you are probably interested in _dragStartPosition too\n   *\n   * @param {Event} event\n   * @param {Msvg.Point} position\n   * @protected\n   */\n  protected _draggingEndedHandler(event: MouseEvent, position: Msvg.Point): void {\n\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { SvgPointerEventNormalizer } from './SvgPointerEventNormalizer';\nimport { PointerEventHelper } from '../util/PointerEventHelper';\n\n/**\n * be careful: this class is dependend on some private properties of the Tool!\n */\nexport class ToolEventDelegator {\n\n  /** @type {import('./Tool').Tool} */\n  _tool;\n  /** @type {import('./ToolGrid').ToolGrid|null} */\n  _grid = null;\n\n  /** @type {TouchEvent|null} */\n  _lastTouchstartTouch = null;\n  /** @type {MouseEvent|null} */\n  _lastMouseDownEvent = null;\n\n  /**\n   * since the click event will still be fired after dragging a lot of distance (why browsers?) we have prevent it manuall\n   *\n   * @type {boolean}\n   * @private\n   */\n  _preventNextMouseClicked = false;\n\n  /**\n   * @param {import('./Tool').Tool} tool\n   */\n  constructor(tool) {\n    this._tool = tool;\n  }\n\n  reset() {\n    this._lastMouseDownEvent = null;\n    this._lastTouchstartTouch = null;\n  }\n\n  /**\n   * @param {MouseEvent} event\n   */\n  mouseClicked(event) {\n    if(this._tool.isActive()) {\n      if(!this._preventNextMouseClicked) {\n        this._tool._mouseClickedHandler(event, this._normalizeMouseEvent(event));\n      } else {\n        this._preventNextMouseClicked = false;\n      }\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   */\n  mouseMoved(event) {\n    if(this._tool.isActive()) {\n      this._updateIsDragging(event, this._lastMouseDownEvent);\n\n      const position = this._normalizeMouseEvent(event);\n      this._tool._mouseMovedHandler(event, position);\n\n      if(this._tool._isDragging) {\n        this._tool._draggingHandler(event, position);\n        this._tool._lastDraggingPosition = position;\n      }\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   */\n  mouseEntered(event) {\n    if(this._tool.isActive()) {\n      this._tool._mouseEnteredHandler(event, this._normalizeMouseEvent(event));\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   */\n  mouseLeft(event) {\n    if(this._tool._active) {\n      this._tool._mouseLeftHandler(event, this._normalizeMouseEvent(event));\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   */\n  mouseDown(event) {\n    if(this._tool.isActive()) {\n      this._lastMouseDownEvent = event;\n      this._tool._dragStartPosition = this._normalizeMouseEvent(event);\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   */\n  mouseUp(event) {\n    if(this._tool.isActive()) {\n      this._lastMouseDownEvent = null;\n      if(this._endMouseDragging(event)) {\n        event.preventDefault(); // prevent event from creating a click event\n      }\n    }\n  }\n\n  // //////////////// Touch events\n\n  /**\n   * @param {Event} event\n   */\n  touchStarted(event) {\n    if(this._tool.isActive()) {\n      // noinspection JSUnresolvedVariable\n      this._lastTouchstartTouch = event.targetTouches[0];\n      this._tool._dragStartPosition = this._normalizeTouchEvent(event);\n      this._tool._touchStartedHandler(event, this._tool._dragStartPosition);\n    }\n  }\n\n  /**\n   * @param {Event} event\n   */\n  touchMoved(event) {\n    if(this._tool.isActive()) {\n      // noinspection JSUnresolvedVariable\n      this._updateIsDragging(event.targetTouches[0], this._lastTouchstartTouch);\n\n      const position = this._normalizeTouchEvent(event);\n      this._tool._touchMovedHandler(event, position);\n\n      if(this._tool._isDragging) {\n        this._tool._draggingHandler(event, position);\n        this._tool._lastDraggingPosition = position;\n      }\n    }\n  }\n\n  /**\n   * do not override this, but the _touchEndedHandler instead\n   *\n   * @param {Event} event\n   */\n  touchEnded(event) {\n    if(this._tool.isActive()) {\n      const position = this._normalizeTouchEvent(event);\n      this._tool._touchEndedHandler(event, position);\n      if(this._tool._isDragging) {\n        this._tool._isDragging = false;\n        // we don't have a position on the touch end, so we use the last dragging position\n        this._tool._draggingEndedHandler(event, this._tool._lastDraggingPosition);\n      }\n    }\n  }\n\n  /**\n   * @param {MouseEvent} event\n   * @returns {boolean}\n   * @private\n   */\n  _endMouseDragging(event) {\n    if(this._tool._isDragging) {\n      this._tool._isDragging = false;\n      this._tool._draggingEndedHandler(event, this._normalizeMouseEvent(event));\n      this._preventNextMouseClicked = true;\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * @param {MouseEvent|*} currentTouchOrMouseEvent\n   * @param {MouseEvent|*} startTouchOrMouseEvent\n   * @private\n   */\n  _updateIsDragging(currentTouchOrMouseEvent, startTouchOrMouseEvent) {\n    if(!this._tool._isDragging && startTouchOrMouseEvent) {\n      const distance = PointerEventHelper.calculateClientDistance(currentTouchOrMouseEvent, startTouchOrMouseEvent);\n      this._tool._isDragging = distance > (this._tool.instantDraggingActivated() ? 0 : PointerEventHelper.minDragDistance);\n      this._tool._lastDraggingPosition = this._tool._dragStartPosition;\n    }\n  }\n\n  /**\n   * normalizes the event to canvas coordinates and aligns it to the grid\n   *\n   * @param {MouseEvent} event\n   * @returns {Msvg.Point}\n   * @private\n   */\n  _normalizeMouseEvent(event) {\n    return this._alignPointToGridAndHighlight(SvgPointerEventNormalizer.normalizeMouseEvent(event, this._tool.getMsvg()));\n  }\n\n  /**\n   * normalizes the event to canvas coordinates and aligns it to the grid\n   *\n   * @param {Event} event\n   * @returns {Msvg.Point}\n   * @private\n   */\n  _normalizeTouchEvent(event) {\n    return this._alignPointToGridAndHighlight(SvgPointerEventNormalizer.normalizeTouchEvent(event, this._tool.getMsvg()));\n  }\n\n  /**\n   * @param {Msvg.Point} normalizedPoint\n   * @returns {Msvg.Point}\n   * @private\n   */\n  _alignPointToGridAndHighlight(normalizedPoint) {\n    if(this._tool._grid.isEnabled() && this._tool._grid.isNearGridPoint(normalizedPoint, 0.5)) {\n      const point = this._tool._grid.alignPointToGrid(normalizedPoint);\n      this._tool._grid.setHighlightedPoint(point);\n      return point;\n    } else {\n      this._tool._grid.setHighlightedPoint(null);\n      return normalizedPoint;\n    }\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n/* global Msvg */\nimport { DelayedQueue } from '../util/DelayedQueue';\n\nexport class ToolGrid {\n\n  /** @type {number} */\n  _desiredGridSize = 0;\n  /** @type {(Msvg.Point|null)} */\n  _highlightedPoint = null;\n\n  /** @type {number} */\n  _gridSize = 0;\n\n  _enabled = false;\n\n  /** @type {Msvg.Msvg} */\n  _svgElement;\n  /** @type {Array<TToolGridGridPoint>} */\n  _gridPoints = [];\n  _gridPointSize = 5;\n  _gridPointWidth = 1;\n\n  /**\n   * the svgElement element for the grid to work on\n   *\n   * will draw the grid on there and also calculate the grid based on the svgElement\n   * will also redraw on the svgElement, so give the grid its own svgElement\n   *\n   * @param {Msvg.Msvg} svgElement\n   */\n  constructor(svgElement) {\n    this._svgElement = svgElement;\n\n    this._gridRenderQueue = new DelayedQueue({\n      workerFunction: this._renderGridPoint.bind(this),\n      chunkSize: 150,\n      timeout: 100\n    });\n\n    this.calculateGrid();\n  }\n\n  /**\n   * size in pixel for the grid lines\n   *\n   * @param {number} size\n   */\n  setLineWidth(size) {\n    this._lineWidth = Math.max(size, 1);\n    this.calculateGrid();\n  }\n\n  /**\n   * set to 0 to deactivate the grid\n   *\n   * @param {number} gridSize\n   */\n  setDesiredGridSize(gridSize) {\n    this._desiredGridSize = gridSize;\n    this.calculateGrid();\n  }\n\n  /**\n   * @returns {number}\n   */\n  getDesiredGridSize() {\n    return this._desiredGridSize;\n  }\n\n  /**\n   *\n   * @param {boolean} enabled\n   */\n  setEnabled(enabled) {\n    this._enabled = enabled;\n  }\n\n  calculateGrid() {\n    if(!this._svgElement) {\n      return;\n    }\n\n    if(this._desiredGridSize !== 0) {\n      const width = this._svgElement.getViewBox().width;\n      const x = width / this._desiredGridSize;\n      this._gridSize = this._roundNumber(width / Math.round(x));\n    } else {\n      this._gridSize = 0;\n    }\n\n    this.reDrawGrid();\n  }\n\n  /**\n   *\n   * approximationFactor should be between (bounds included) 0.1 and 1\n   *\n   * @param {Msvg.Point} point\n   * @param {number} approximationFactor\n   * @returns {boolean}\n   */\n  isNearGridPoint(point, approximationFactor) {\n    approximationFactor /= 2; // conversion from percent into a comma value\n    if(this._gridSize <= 30) {\n      approximationFactor = 0.5; // grid is to small to use the factor\n    }\n\n    return this._checkCoordinateIsCloseToGrid(point.x, approximationFactor) &&\n      this._checkCoordinateIsCloseToGrid(point.y, approximationFactor);\n  }\n\n  /**\n   *   *\n   * @param {number} coordinate\n   * @param {number} approximationFactor\n   * @returns {boolean}\n   */\n  _checkCoordinateIsCloseToGrid(coordinate, approximationFactor) {\n    const divisionResult = coordinate / this._gridSize;\n    let commaValue = divisionResult - Math.floor(divisionResult); // we only have the comma parts now\n    commaValue = commaValue >= 0.5 ? 1 - commaValue : commaValue; // normalize the comma value into the percentual distance to the next point\n\n    return commaValue === 0 || commaValue <= approximationFactor;\n  }\n\n  /**\n   * align the point to the nearest grid point\n   *\n   * @param {Msvg.Point} point\n   * @return {Msvg.Point}\n   */\n  alignPointToGrid(point) {\n    return new Msvg.Point(\n      Math.round(point.x / this._gridSize) * this._gridSize,\n      Math.round(point.y / this._gridSize) * this._gridSize\n    );\n  }\n\n  isEnabled() {\n    return this._enabled && this._gridSize > 0;\n  }\n\n  /**\n   *\n   * @param {(Msvg.Point|null)} point\n   */\n  setHighlightedPoint(point) {\n    if(point) {\n      this._highlightedPoint = new Msvg.Point(\n        this._roundNumber(point.x),\n        this._roundNumber(point.y)\n      );\n    } else {\n      this._highlightedPoint = null;\n    }\n\n    this._updateHighlightedGridPoint();\n  }\n\n  reDrawGrid() {\n    this._svgElement.empty();\n    this._gridPoints = [];\n    this._gridRenderQueue.clear();\n\n    if(this._gridSize <= 0) {\n      return;\n    }\n\n    const viewBox = this._svgElement.getViewBox();\n    const yPoints = this._calculateGridCoordinatesForLength(viewBox.height);\n    const xPoints = this._calculateGridCoordinatesForLength(viewBox.width);\n\n    yPoints.forEach((y) => {\n      xPoints.forEach((x) => {\n        this._gridRenderQueue.queue(new Msvg.Point(x, y));\n      });\n    });\n\n    this._updateHighlightedGridPoint();\n  }\n\n  _updateHighlightedGridPoint() {\n    this._gridPoints.forEach((gridPoint) => {\n      if(this._highlightedPoint && gridPoint.x === this._highlightedPoint.x && gridPoint.y === this._highlightedPoint.y) {\n        this._setPathHighlightStyling(gridPoint.path, gridPoint.x, gridPoint.y);\n        gridPoint.isHighlighted = true;\n      } else if(gridPoint.isHighlighted) {\n        this._setPathDefaultStyling(gridPoint.path, gridPoint.x, gridPoint.y);\n        gridPoint.isHighlighted = false;\n      }\n    });\n  }\n\n  /**\n   *\n   * @param {Msvg.Point} point\n   * @private\n   */\n  _renderGridPoint(point) {\n    this._gridPoints.push({\n      x: point.x,\n      y: point.y,\n      isHighlighted: false,\n      path: this._generateGridPointPath(point.x, point.y)\n    });\n  }\n\n  /**\n   *\n   * @param {number} x\n   * @param {number} y\n   * @returns {Msvg.Path}\n   * @private\n   */\n  _generateGridPointPath(x, y) {\n    const path = new Msvg.Path();\n    this._setPathDefaultStyling(path, x, y);\n    this._svgElement.append(path);\n    return path;\n  }\n\n  /**\n   *\n   * @param {Msvg.Path} path\n   * @param {number} x\n   * @param {number} y\n   * @private\n   */\n  _setPathDefaultStyling(path, x, y) {\n    path.setFill('rgba(127,127,127,0.4)')\n      .setStrokeWidth(0);\n\n    this._addCrosshairToPath(path, x, y, this._gridPointWidth);\n  }\n\n  /**\n   *\n   * @param {Msvg.Path} path\n   * @param {number} x\n   * @param {number} y\n   * @private\n   */\n  _setPathHighlightStyling(path, x, y) {\n    path.setFill('rgba(0, 0, 0)')\n      .setStroke('white')\n      .setStrokeWidth(1);\n\n\n    this._addCrosshairToPath(path, x, y, this._gridPointWidth * 2);\n  }\n\n  /**\n   *\n   * @param {Msvg.Path} path\n   * @param {number} x\n   * @param {number} y\n   * @param {number} width\n   * @private\n   */\n  _addCrosshairToPath(path, x, y, width) {\n    /*       _\n     *      | |\n     *  ____| |____\n     * |____   ____|\n     *      | |\n     *      |_|\n     */\n\n    const widthOffset = width / 2;\n    path.createFastBuilder()\n      .addMoveToAbsolute(new Msvg.Point(x - widthOffset, y - widthOffset))\n      .addLineToAbsolute(new Msvg.Point(x - widthOffset, y - this._gridPointSize))\n      .addLineToAbsolute(new Msvg.Point(x + widthOffset, y - this._gridPointSize))\n      .addLineToAbsolute(new Msvg.Point(x + widthOffset, y - widthOffset))\n      .addLineToAbsolute(new Msvg.Point(x + this._gridPointSize, y - widthOffset))\n      .addLineToAbsolute(new Msvg.Point(x + this._gridPointSize, y + widthOffset))\n      .addLineToAbsolute(new Msvg.Point(x + widthOffset, y + widthOffset))\n      .addLineToAbsolute(new Msvg.Point(x + widthOffset, y + this._gridPointSize))\n      .addLineToAbsolute(new Msvg.Point(x - widthOffset, y + this._gridPointSize))\n      .addLineToAbsolute(new Msvg.Point(x - widthOffset, y + widthOffset))\n      .addLineToAbsolute(new Msvg.Point(x - this._gridPointSize, y + widthOffset))\n      .addLineToAbsolute(new Msvg.Point(x - this._gridPointSize, y - widthOffset))\n      .addClosePath()\n      .finish();\n  }\n\n  /**\n   *\n   * @param {number} length\n   * @returns {Array<number>}\n   * @private\n   */\n  _calculateGridCoordinatesForLength(length) {\n    const points = [];\n\n    for(let y = 0; y <= length; y += this._gridSize) {\n      points.push(this._roundNumber(y));\n    }\n\n    return points;\n  }\n\n  /**\n   *\n   * @param {number} value\n   * @return {number}\n   * @private\n   */\n  _roundNumber(value) {\n    return Math.round(value * 10) / 10; // round to the first comma digit\n  }\n\n}\n\n/**\n * @typedef {Object} TToolGridGridPoint\n * @property {number} y\n * @property {number} x\n * @property {boolean} isHighlighted\n * @property {Msvg.Path} path\n */\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nexport interface TDelayedQueueOptions {\n  workerFunction: ((arg0: unknown) => void) | null;\n  chunkSize: number | null;\n  timeout: number | null;\n}\n\n/**\n * a class which helps with queueing items and processing them later on to keep the UI responsive\n * this is only useful for time insensitive operations, like rendering something for the user\n */\nexport class DelayedQueue {\n\n  private static defaultOptions: TDelayedQueueOptions = {\n    workerFunction: null,\n    chunkSize: 10,\n    timeout: 50,\n  };\n\n  private _items: Array<unknown> = [];\n  private _options: TDelayedQueueOptions;\n  private _queueInProgress = false;\n  private _processItemsTimeout: number | null = null;\n\n  /**\n   *\n   * @param {TDelayedQueueOptions} options\n   */\n  constructor(options: TDelayedQueueOptions) {\n    this._options = { ...DelayedQueue.defaultOptions, ...options };\n  }\n\n  public queue(item: unknown): void {\n    this._items.push(item);\n    this._startProcessItemsLoop();\n  }\n\n  /**\n   * will queue the item at the index given by the offset, if the offset = 0, the item will be queued in front of everything else\n   * useful if you need to queue something with priority\n   *\n   * @param {*} item\n   * @param {number} [offset] - a positive number\n   */\n  public queueInFront(item: unknown, offset = 0): void {\n    if(offset < this._items.length) {\n      this._items.splice(offset, 0, item);\n    } else {\n      this._items.push(item);\n    }\n\n    this._startProcessItemsLoop();\n  }\n\n  /**\n   * @param {*} item\n   */\n  public remove(item: unknown): void {\n    // item can be multiple times in the queue and we want to remove all of them\n    while(true) {\n      const index = this._items.indexOf(item);\n\n      if(index >= 0) {\n        this._items.splice(index, 1);\n      } else {\n        break;\n      }\n    }\n  }\n\n  public flush(): void {\n    while(this._items.length) {\n      this._workNextItem();\n    }\n\n    this.clear();\n  }\n\n  public clear(): void {\n    this._items.length = 0;\n    this._queueInProgress = false;\n    clearTimeout(this._processItemsTimeout);\n  }\n\n  /**\n   * @private\n   */\n  private _startProcessItemsLoop(): void {\n    if(!this._queueInProgress) {\n      this._startProcessItemsTimeout();\n      this._queueInProgress = true;\n    }\n  }\n\n  /**\n   * @private\n   */\n  private _startProcessItemsTimeout(): void {\n    this._processItemsTimeout = setTimeout(() => {\n      this._processItems();\n    }, this._options.timeout);\n  }\n\n  /**\n   * @private\n   */\n  private _processItems(): void {\n    this._workNextItems();\n\n    // the queueInProgress check here is only here in case the worker triggers a flush/clear\n    if(this._items.length && this._queueInProgress) {\n      this._startProcessItemsTimeout();\n    } else {\n      this._queueInProgress = false;\n      this._processItemsTimeout = null;\n    }\n  }\n\n  /**\n   * @private\n   */\n  private _workNextItems(): void {\n    for(let key = 0; key < this._options.chunkSize; key++) {\n      this._workNextItem();\n    }\n  }\n\n  /**\n   * @private\n   */\n  private _workNextItem(): void {\n    if(this._items.length === 0) {\n      return;\n    }\n\n    try {\n      this._options.workerFunction?.(this._items.shift());\n    } catch(e) {\n      console.error(e);\n    }\n  }\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nexport class DomEventHelper {\n\n  /**\n   * create an event object to fire\n   *\n   * shamelessly stolen from:\n   * https://ilikekillnerds.com/2015/08/aurelia-custom-elements-custom-callback-events-tutorial/\n   *\n   */\n  public static createEvent<T extends CustomEvent>(name: string, bubbles: boolean, detail: T['detail']): T {\n    let event;\n\n    if((window).CustomEvent) {\n      event = new CustomEvent(name, {\n        cancelable: true,\n        detail: detail,\n        bubbles: bubbles,\n      });\n    } else {\n      event = document.createEvent('CustomEvent');\n      event.initCustomEvent(name, bubbles, true, {\n        detail,\n      });\n    }\n\n    return event as T;\n  }\n\n  public static fireEvent<T extends CustomEvent>(element: Element, options: IFireEventOptions<T>): T {\n    const event = DomEventHelper.createEvent(options.name, !!options.bubbles, options.detail);\n    element.dispatchEvent(event);\n    return event;\n  }\n\n}\n\nexport interface IFireEventOptions<T extends CustomEvent> {\n  name: T['type'];\n  bubbles?: boolean;\n  detail: T['detail'];\n}\n\nexport type NamedCustomEvent<TName extends string, TDetail> = CustomEvent<TDetail> & { type: TName };\n","/**\n * Adapted from recordIT\n */\n\nimport { EventDispatcher } from './EventDispatcher';\nimport '../msvg/msvg';\n\nexport class DrawingHistoryManager {\n\n  private static readonly HISTORY_SIZE = 20;\n\n  private history: Array<SVGSVGElement> = [];\n\n  private msvg: Msvg.Msvg;\n  private dispatcher: EventDispatcher<{ changed: null; 'msvg-modified': null }> = new EventDispatcher();\n  private currentIndex = -1;\n\n  constructor(msvg: Msvg.Msvg) {\n    this.msvg = msvg;\n    this.push();\n  }\n\n  public reset(): void {\n    this.history = [];\n    this.push();\n    this.dispatcher.dispatchEvent('changed', null);\n    this.dispatcher.dispatchEvent('msvg-modified', null);\n  }\n\n  /**\n   * saves the current state into the history\n   * also removes the forward queue if there was one\n   */\n  public push(): void {\n    this.removeRedoHistory();\n\n    if(this.history.length >= DrawingHistoryManager.HISTORY_SIZE) {\n      this.history.shift();\n    }\n\n    this.currentIndex = this.history.length;\n    this.history.splice(this.currentIndex, 1, this.msvg.getElement().cloneNode(true) as SVGSVGElement);\n    this.fireChangedEvent();\n  }\n\n  /**\n   * loads the last state into the canvas\n   */\n  public undo(): void {\n    if(!this.canUndo()) {\n      return;\n    }\n\n    this.currentIndex = Math.max(this.currentIndex - 1, 0);// never remove the first item\n    this.loadHistoryItem(this.history[this.currentIndex]);\n    this.fireChangedEvent();\n  }\n\n  /**\n   * loads the next step (if one exists) into the canvas\n   */\n  public redo(): void {\n    if(!this.canRedo()) {\n      return;\n    }\n\n    const nextItem = this.history[this.currentIndex + 1];\n\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n    if(nextItem) {\n      ++this.currentIndex;\n      this.loadHistoryItem(nextItem);\n    }\n    this.fireChangedEvent();\n  }\n\n  public canUndo(): boolean {\n    return this.currentIndex >= 1;\n  }\n\n  public canRedo(): boolean {\n    return this.currentIndex < (this.history.length - 1);\n  }\n\n  /**\n   * fired everytime when the history status changed (e.g. a new state has been pushed)\n   */\n  public addChangedListener(context: unknown, callback: () => void): void {\n    this.dispatcher.addEventListener(context, 'changed', callback);\n  }\n\n  /**\n   * only fired when an history item has been loaded into the msvg\n   */\n  public addMsvgModifiedListener(context: unknown, callback: () => void): void {\n    this.dispatcher.addEventListener(context, 'msvg-modified', callback);\n  }\n\n  public removeEventListeners(context: unknown): void {\n    this.dispatcher.removeEventListenersByContext(context);\n  }\n\n  private fireChangedEvent(): void {\n    this.dispatcher.dispatchEvent('changed', null);\n  }\n\n  private loadHistoryItem(item: SVGSVGElement): void {\n    this.msvg.empty();\n\n    const svg = this.msvg.getElement();\n    // we don't want modify the item because else the content would be lost when redoing and undoing the history\n    const itemClone = item.cloneNode(true);\n    while(itemClone.firstChild) {\n      svg.appendChild(itemClone.firstChild);\n    }\n\n    this.dispatcher.dispatchEvent('msvg-modified', null);\n  }\n\n  private removeRedoHistory(): void {\n    if(this.canRedo()) { // there must be new data on top of the currentIndex, remove it\n      this.history.splice(this.currentIndex + 1, this.history.length - this.currentIndex - 1);\n    }\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n\nexport class EventDispatcher<TEventConfig> {\n\n  private eventListeners: Array<IEventListener<TEventConfig>> = [];\n\n  public addEventListener<T extends keyof TEventConfig>(context: unknown, eventName: T, callback: (payload: TEventConfig[T]) => void): void {\n    this.eventListeners.push({\n      context,\n      eventName,\n      callback,\n    });\n  }\n\n  public removeEventListenersByContext(context: unknown): void {\n    this.removeEventListenerWithCallback(listener => {\n      return listener.context === context;\n    });\n  }\n\n  public dispatchEvent<T extends keyof TEventConfig>(eventName: T, payload: TEventConfig[T]): void {\n    for(const listener of this.eventListeners) {\n      if(listener.eventName === eventName) {\n        // TODO apply context\n        listener.callback(payload);\n      }\n    }\n  }\n\n  /**\n   * callback gets called for every listener\n   * if the callback returns true the event listener will get removed\n   */\n  private removeEventListenerWithCallback(callback: CallbackFunction<TEventConfig>): void {\n    for(let i = this.eventListeners.length - 1; i >= 0; i--) {\n      if(callback(this.eventListeners[i])) {\n        this.eventListeners.splice(i, 1);\n      }\n    }\n  }\n\n}\n\ninterface IEventListener<TEventConfig, TKey extends keyof TEventConfig = any> {\n  context: any;\n  eventName: TKey;\n  callback: (payload: TEventConfig[TKey]) => void;\n}\n\ntype CallbackFunction<T> = (listener: IEventListener<T>) => boolean;\n","/**\n * Adapted from recordIT\n */\n\nexport class AngleHelper {\n\n  /**\n   *\n   * @param {number} deg\n   * @returns {number}\n   */\n  public static degToRad(deg: number): number {\n    return (deg * Math.PI) / 180;\n  }\n\n  public static radToDeg(rad: number): number {\n    return (rad * 180) / Math.PI;\n  }\n\n  /**\n   * flip the angle from the clockwise to the counter clockwise representation (and vice versa)\n   *\n   * e.g. because the transform angle is clockwise and vector angles are counter clockwise we have to convert it\n   */\n  public static flipAngle(angle: number): number {\n    return this.simplifyDegAngle(360 - this.simplifyDegAngle(angle));\n  }\n\n  /**\n   * converts the angle to a 0 - 360 range\n   */\n  public static simplifyDegAngle(angle: number): number {\n    const simplified = angle % 360;\n    if(simplified < 0) {\n      return simplified + 360;\n    }\n    return simplified;\n  }\n}\n","/**\n * Adapted from recordIT\n */\n\nimport { AngleHelper } from './AngleHelper';\n\nexport interface IScale {\n  scaleX: number;\n  scaleY: number;\n}\n\nexport interface IMatrixElements {\n  a: number;\n  b: number;\n  c: number;\n  d: number;\n  tx: number;\n  ty: number;\n}\n\nexport interface ISkew {\n  skewX: number;\n  skewY: number;\n}\n\nexport interface ITranslate {\n  translateX: number;\n  translateY: number;\n}\n\nexport interface IPoint {\n  x: number;\n  y: number;\n}\n\nexport type TTransformParameters = IScale & ISkew & ITranslate;\n\nexport class TransformHelper {\n\n  /**\n   * @param {string} matrix\n   * @returns {number|null}\n   */\n  public static getRotationFromTransformMatrix(matrix: string): number|null {\n    const values = this.getMatrixElements(matrix);\n    if(!values) {\n      return null;\n    }\n\n    return AngleHelper.radToDeg(Math.atan2(values.b, values.a));\n  }\n\n  /**\n   * @param {string} matrix\n   * @returns {TScale|null}\n   */\n  public static getScaleFromTransformMatrix(matrix: string): IScale | null {\n    const values = this.getMatrixElements(matrix);\n    if(!values) return null;\n\n    const transformParameters = this.decomposeMatrix(values);\n\n    return {\n      scaleX: transformParameters.scaleX,\n      scaleY: transformParameters.scaleY,\n    };\n  }\n\n  /**\n   * @param {string} matrix\n   * @returns {TMatrixElements|null}\n   */\n  private static getMatrixElements(matrix: string): IMatrixElements | null {\n    const values = this.parseMatrixString(matrix);\n    if(!values) return null;\n\n    return {\n      a: parseFloat(values[1]),\n      b: parseFloat(values[2]),\n      c: parseFloat(values[3]),\n      d: parseFloat(values[4]),\n      tx: parseFloat(values[5]),\n      ty: parseFloat(values[6]),\n    };\n  }\n\n  private static parseMatrixString(matrix: string): RegExpExecArray | null {\n    return /matrix\\(([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^,]*), ([^,]*)\\)/.exec(matrix);\n  }\n\n  private static deltaTransformPoint(matrix: IMatrixElements, point: IPoint): IPoint {\n    const dx = point.x * matrix.a + point.y * matrix.c + 0;\n    const dy = point.x * matrix.b + point.y * matrix.d + 0;\n    return { x: dx, y: dy };\n  }\n\n  /**\n   * @see https://gist.github.com/2052247\n   *\n   * @param {TMatrixElements} matrix\n   * @returns {TTransformParameters}\n   */\n  private static decomposeMatrix(matrix: IMatrixElements): TTransformParameters {\n    // calculate delta transform point\n    const px = this.deltaTransformPoint(matrix, { x: 0, y: 1 });\n    const py = this.deltaTransformPoint(matrix, { x: 1, y: 0 });\n\n    // calculate skew\n    const skewX = ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);\n    const skewY = ((180 / Math.PI) * Math.atan2(py.y, py.x));\n\n    return {\n      translateX: matrix.tx,\n      translateY: matrix.ty,\n      scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),\n      scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),\n      skewX,\n      skewY,\n    };\n  }\n}\n","/**\n * Adapted from recordIT\n */\n\n/* eslint-disable no-underscore-dangle */\nimport { AngleHelper } from './AngleHelper';\n\nexport interface IVectorOptions {\n  mode: 'default' | 'html';\n  allowAngleFunctions: boolean;\n}\n\n/**\n * all Methods without an explicit value will return the instance\n */\nexport class Vector {\n\n  static defaultOptions: IVectorOptions = {\n    mode: 'default',\n    allowAngleFunctions: true,\n  };\n\n  private _x = 0;\n  private _y = 0;\n  private _options: IVectorOptions;\n\n  /**\n   *\n   * @param {number} x\n   * @param {number} y\n   * @param {TVectorOptions} [opts]\n   */\n  constructor(x: number, y: number, opts?: Partial<IVectorOptions>) {\n    this._x = x;\n    this._y = y;\n    this._options = { ...Vector.defaultOptions, ...opts };\n  }\n\n  private setX(x: number): Vector {\n    this._x = x;\n\n    return this;\n  }\n\n  private getX(): number {\n    return this._x;\n  }\n\n  public setY(y: number): Vector {\n    this._y = y;\n\n    return this;\n  }\n\n  public getY(): number {\n    return this._y;\n  }\n\n  public setXY(x: number, y: number): Vector {\n    this._x = x;\n    this._y = y;\n\n    return this;\n  }\n\n  public clone(): Vector {\n    return new Vector(this._x, this._y, this._options);\n  }\n\n  public addVector(vector: Vector): Vector {\n    this.setX(this.getX() + vector.getX());\n    this.setY(this.getY() + vector.getY());\n\n    return this;\n  }\n\n  public substractVector(vector: Vector): Vector {\n    this.setX(this.getX() - vector.getX());\n    this.setY(this.getY() - vector.getY());\n\n    return this;\n  }\n\n  public multiplyVector(vector: Vector): Vector {\n    this.setX(this.getX() * vector.getX());\n    this.setY(this.getY() * vector.getY());\n\n    return this;\n  }\n\n  public divideVector(vector: Vector): Vector {\n    this.setX(this.getX() / vector.getX());\n    this.setY(this.getY() / vector.getY());\n\n    return this;\n  }\n\n  public divideXY(x: number, y: number): Vector {\n    this.setX(this.getX() / x);\n    this.setY(this.getY() / y);\n\n    return this;\n  }\n\n  public addXY(x: number, y: number): Vector {\n    this.setX(this.getX() + x);\n    this.setY(this.getY() + y);\n\n    return this;\n  }\n\n  public substractXY(x: number, y: number): Vector {\n    this.setX(this.getX() - x);\n    this.setY(this.getY() - y);\n\n    return this;\n  }\n\n  public multiplyXY(x: number, y: number): Vector {\n    this.setX(this.getX() * x);\n    this.setY(this.getY() * y);\n\n    return this;\n  }\n\n  /**\n   * scales x and y by the factor\n   */\n  public scale(factor: number): Vector {\n    this.setX(this.getX() * factor);\n    this.setY(this.getY() * factor);\n\n    return this;\n  }\n\n  /**\n   * @param {number} angle - in degrees\n   */\n  public rotate(angle: number): Vector {\n    this._checkCanUseAngleFunctions();\n    this.setAngle(this.getAngle() ?? 0 + angle);\n\n    return this;\n  }\n\n  /**\n   *\n   * @param {number} angle - in degrees\n   * @returns {Vector} - this\n   */\n  public setAngle(angle: number): Vector {\n    this._checkCanUseAngleFunctions();\n    const length = this.getLength();\n    const modificator = this._getXYModificatorForAngleCalculation();\n    this.setX(Math.cos(AngleHelper.degToRad(angle)) * length * modificator.x);\n    this.setY(Math.sin(AngleHelper.degToRad(angle)) * length * modificator.y);\n\n    return this;\n  }\n\n  /**\n   *\n   * @returns {number}\n   */\n  public getLength(): number {\n    return Math.sqrt(this._x ** 2 + this._y ** 2);\n  }\n\n  /**\n   * returns null if no angle could be calculated (e.g. for a vector with length 0)\n   * @returns {(number|null)}\n   */\n  public getAngle(): number | null {\n    this._checkCanUseAngleFunctions();\n    const modificator = this._getXYModificatorForAngleCalculation();\n\n    const xCalc = this._x * modificator.x;\n    const yCalc = this._y * modificator.y;\n\n    if(xCalc === 0) {\n      if(yCalc === 0) {\n        return null;\n      }\n\n      return yCalc > 0 ? 90 : 270;\n    }\n\n    if(yCalc === 0) {\n      return xCalc > 0 ? 0 : 180;\n    }\n\n    const angle = AngleHelper.radToDeg(Math.atan(yCalc / xCalc));\n\n    if(xCalc < 0 && yCalc > 0) { // quadrant 2\n      return angle + 180;\n    }\n    if(xCalc < 0 && yCalc < 0) { // quadrant 3\n      return angle + 180;\n    }\n    if(angle < 0) { // quadrant 4\n      return angle + 360;\n    }\n    return angle;\n  }\n\n  /**\n   *\n   * @returns {{x: number, y: number}}\n   */\n  public toPlainObject(): {x: number; y: number} {\n    return {\n      x: this.getX(),\n      y: this.getY(),\n    };\n  }\n\n  private _checkCanUseAngleFunctions(): void {\n    if(!this._options.allowAngleFunctions) {\n      throw new Error('[Vector] this vector can\\'t use angle functions');\n    }\n  }\n\n  private _getXYModificatorForAngleCalculation(): {x: number; y: number} {\n    switch(this._options.mode) {\n      case 'html':\n        return {\n          x: 1,\n          y: -1,\n        };\n\n      case 'default':\n      default:\n        return {\n          x: 1,\n          y: 1,\n        };\n    }\n  }\n\n  public static createFromLongitudeLatitude(latLong: {latitude: number; longitude: number}): Vector {\n    return new Vector(latLong.longitude, latLong.latitude, { mode: 'default', allowAngleFunctions: false });\n  }\n\n  /**\n   *\n   * @param {number} x\n   * @param {number} y\n   * @returns {Vector}\n   */\n  public static createHtmlVector(x: number, y: number): Vector {\n    return new Vector(x, y, { mode: 'html' });\n  }\n\n  /**\n   * @param {TPlainVector} plainVector\n   * @returns {Vector}\n   */\n  private static createFromPlainVector(plainVector: {x: number; y: number}): Vector {\n    return new Vector(\n      plainVector.x,\n      plainVector.y,\n    );\n  }\n}\n\n/**\n * because the coordinate system in html/js is shifted (increasing y moves things to the bottom), the rotate/setAngle feature will break\n *\n * @typedef {Object} TVectorOptions\n * @property {string} mode - possibleValues 'default', 'html'\n * @property {boolean} [allowAngleFunctions]\n */\n\n/**\n * @typedef {Object} TPlainVector\n * @property {number} x\n * @property {number} y\n */\n","/**\n * Adapted from recordIT\n */\n\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { SvgCleaner } from './Svg/SvgCleaner';\n\nexport class ImageHelper {\n\n  /**\n   * make sure both images have the same ratio because the second image will completely cover the first one\n   *\n   * returns a dataUrl of type image/jpeg\n   */\n  public static mergeImages(imageElement: HTMLImageElement, imageElement2: HTMLImageElement): string {\n    const canvas = document.createElement('canvas');\n    canvas.width = imageElement.naturalWidth;\n    canvas.height = imageElement.naturalHeight;\n\n    const ctx = canvas.getContext('2d');\n    assertNotNullOrUndefined(ctx, 'drawing context does not exist');\n\n    ctx.drawImage(imageElement, 0, 0, canvas.width, canvas.height);\n    ctx.drawImage(imageElement2, 0, 0, canvas.width, canvas.height);\n    return canvas.toDataURL('image/jpeg');\n  }\n\n  /**\n   * the result is the canvas drawn over the image (it will get stretched, so make sure both have the same ration)\n   *\n   * returns a dataUrl of type image/jpeg\n   */\n  public static mergeImageAndCanvas(imageElement: HTMLImageElement, canvasElement: HTMLCanvasElement): string {\n    const canvas = document.createElement('canvas');\n    canvas.width = imageElement.naturalWidth;\n    canvas.height = imageElement.naturalHeight;\n\n    const ctx = canvas.getContext('2d');\n    assertNotNullOrUndefined(ctx, 'drawing context does not exist');\n\n    ctx.drawImage(imageElement, 0, 0, canvas.width, canvas.height);\n    ctx.drawImage(canvasElement, 0, 0, canvas.width, canvas.height);\n    return canvas.toDataURL('image/jpeg');\n  }\n\n  /**\n   * this function returns a dataUrl of type image/jpeg of the currently show image in the videoElement\n   */\n  public static getCurrentVideoImage(videoElement: HTMLVideoElement): string {\n    const canvas = document.createElement('canvas');\n    canvas.width = videoElement.videoWidth;\n    canvas.height = videoElement.videoHeight;\n\n    const ctx = canvas.getContext('2d');\n    assertNotNullOrUndefined(ctx, 'drawing context does not exist');\n\n    ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);\n\n    return canvas.toDataURL('image/jpeg');\n  }\n\n  /**\n   * rotates the canvas context to the rotation (rotation anchor point is in the center)\n   * and restores the state after the drawingFunction\n   */\n  public static drawInRotatedCanvas(canvas: HTMLCanvasElement, rotation: number, drawingFunction: (ctx: CanvasRenderingContext2D) => void): void {\n    const halfCanvasWidth = canvas.width / 2;\n    const halfCanvasHeight = canvas.height / 2;\n    const radianRotation = (rotation / 180) * Math.PI;\n\n    const ctx = canvas.getContext('2d');\n    assertNotNullOrUndefined(ctx, 'drawing context does not exist');\n\n    ctx.translate(halfCanvasWidth, halfCanvasHeight);\n    ctx.rotate(radianRotation);\n    drawingFunction(ctx);\n    ctx.rotate(-radianRotation);\n    ctx.translate(-halfCanvasWidth, -halfCanvasHeight);\n  }\n\n  public static svgElementToDataUrl(svgElement: SVGSVGElement): string {\n    const svgWrapper = document.createElement('div');\n    svgWrapper.appendChild(svgElement.cloneNode(true));\n    const cleaner = new SvgCleaner();\n    const svgString = `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\\n${cleaner.clean(svgWrapper.innerHTML)}`;\n\n    // encodeURIComponent/unescape is here to prevent encoding issues and make sure that an UTF-8 string gets outputted\n    // without this m², ÖÄÜ etc. wouldn't work\n    return `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgString)))}`;\n  }\n\n  public static imageToDataUrl(image: HTMLImageElement): string {\n    const canvas = document.createElement('canvas');\n    canvas.width = image.naturalWidth;\n    canvas.height = image.naturalHeight;\n\n    const ctx = canvas.getContext('2d');\n    assertNotNullOrUndefined(ctx, 'drawing context does not exist');\n\n    ctx.drawImage(image, 0, 0, canvas.width, canvas.height);\n\n    return canvas.toDataURL('image/png');\n  }\n\n  public static getFileExtensionForDataUrl(dataUrl: string): string|null {\n    const result = /^data:image\\/([a-zA-Z]+)/.exec(dataUrl);\n    let ext = null;\n\n    if(result && result[1]) {\n      // eslint-disable-next-line prefer-destructuring\n      ext = result[1];\n\n      if(ext === 'jpeg') {\n        ext = 'jpg';\n      }\n    }\n\n    return ext;\n  }\n\n  public static loadImage(src: string): Promise<HTMLImageElement> {\n    return new Promise((resolve, reject) => {\n      const img = new Image();\n      img.onload = () => resolve(img);\n      img.onerror = error => reject(error);\n      img.src = src;\n    });\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { Vector } from './Geometry/Vector';\n\nexport class PointerEventHelper {\n\n  /**\n   * the distance we assume that is safe to say that the user wants to drag something instead of clicking it\n   *\n   * @type {number}\n   */\n  static minDragDistance = 50;\n\n  /**\n   *\n   * @param {MouseEvent} event\n   * @returns {boolean}\n   */\n  static leftMouseButtonIsPressed(event) {\n    return (event.buttons & 1) != 0;\n  }\n\n  /**\n   *\n   * @param {{x: number, y: number}} pos1\n   * @param {{x: number, y: number}} pos2\n   * @returns {number}\n   */\n  static calculateDistance(pos1, pos2) {\n    let diffX = pos1.x - pos2.x;\n    let diffY = pos1.y - pos2.y;\n    return Math.sqrt(diffX * diffX + diffY * diffY);\n  }\n\n  /**\n   *\n   * @param {{clientX: number, clientY: number}} p1\n   * @param {{clientX: number, clientY: number}} p2\n   * @returns {number}\n   */\n  static calculateClientDistance(p1, p2) {\n    return PointerEventHelper.calculateDistance({\n      x: p1.clientX,\n      y: p1.clientY\n    }, {\n      x: p2.clientX,\n      y: p2.clientY\n    });\n  }\n\n\n  /**\n   * interpolates the mousepoints between the old and new position linearly\n   *\n   * @param {{x: number, y: number}} oldPosition\n   * @param {{x: number, y: number}} newPosition\n   * @returns {{x: number, y: number}[]}\n   */\n  static interpolateMousePoints(oldPosition, newPosition) {\n    let diffX = oldPosition.x - newPosition.x;\n    let diffY = oldPosition.y - newPosition.y;\n\n    let distance = PointerEventHelper.calculateDistance(oldPosition, newPosition);\n    let angle = Math.asin(Math.abs(diffY) / distance); //ignore the sign for now\n\n    //determines how many points should be interpolated per distance (but in inverse)\n    let iterationFactor = 2;\n    let iterations = distance / iterationFactor;\n\n    let points = [];\n\n    //key starts at 1 to exclude oldPosition\n    for(let key = 1; key < iterations; key++) {\n      let currentDistance = key * iterationFactor;\n      points.push({\n        x: oldPosition.x - Math.cos(angle) * currentDistance * Math.sign(diffX),\n        y: oldPosition.y - Math.sin(angle) * currentDistance * Math.sign(diffY)\n      });\n    }\n\n    return points;\n  }\n\n  /**\n   *\n   * @param {MouseEvent} event\n   * @param {ClientRect} boundingRect\n   * @returns {boolean}\n   */\n  static mouseIsInsideClientRect(event, boundingRect) {\n    return this.clientPointIsInsideClientRect(Vector.createHtmlVector(event.clientX, event.clientY), boundingRect);\n  }\n\n  /**\n   *\n   * @param {Touch} touch\n   * @param {ClientRect} boundingRect\n   * @returns {boolean}\n   */\n  static touchIsInsideClientRect(touch, boundingRect) {\n    return this.clientPointIsInsideClientRect(Vector.createHtmlVector(touch.clientX, touch.clientY), boundingRect);\n  }\n\n  /**\n   *\n   * @param {Vector} point\n   * @param {ClientRect} boundingRect\n   * @returns {boolean}\n   */\n  static clientPointIsInsideClientRect(point, boundingRect) {\n    return point.getX() >= boundingRect.left && point.getX() <= (boundingRect.left + boundingRect.width)\n      && point.getY() >= boundingRect.top && point.getY() <= (boundingRect.top + boundingRect.height);\n  }\n\n  /**\n   *\n   * @param {(MouseEvent|TouchEvent)} event\n   * @returns {Vector}\n   */\n  static getClientPositionFromEvent(event) {\n    let x = 0, y = 0;\n\n    if(event.touches) {\n      x = event.touches[0].clientX;\n      y = event.touches[0].clientY;\n    } else {\n      x = event.clientX;\n      y = event.clientY;\n    }\n\n    return Vector.createHtmlVector(x, y);\n  }\n}\n","/**\n * Adapted from recordIT\n */\n\n/**\n * this class is necessary because some browsers *cough* safari *cough* are too dumb to handle namespaces correctly\n * because apparently it's a good idea to name the href attribute in the xlink namespace `NS1:href` because `xlink:href` would be too cool\n */\nexport class SvgCleaner {\n\n  public clean(str: string): string {\n    return this.fixHrefs(str);\n  }\n\n  private fixHrefs(str: string): string {\n    return str.replace(/NS\\d+:href/gi, 'xlink:href');\n  }\n\n}\n","/**\n * Adapted from recordIT\n */\n/* eslint-disable */\n// @ts-nocheck\n\nexport class Utils {\n\n  public static getRelativeElementOffset(element: HTMLElement, relativeElement: HTMLElement): { top: number, left: number } {\n    const elementOffset = this.getElementOffset(element);\n    const relativeOffset = this.getElementOffset(relativeElement);\n\n    return {\n      top: elementOffset.top - relativeOffset.top,\n      left: elementOffset.left - relativeOffset.left\n    };\n  }\n\n  /**\n   * since jquery.offset() can't handle our layout or is generally broken, we have to implement it ourselves\n   */\n  public static getElementOffset(element: HTMLElement): { top: number, left: number } {\n    const offset = { top: 0, left: 0 };\n    let currentElement: HTMLElement|null = element;\n\n    do {\n      if(currentElement.offsetTop) {\n        offset.top += currentElement.offsetTop;\n      }\n\n      if(currentElement.offsetLeft) {\n        offset.left += currentElement.offsetLeft;\n      }\n\n    } while((currentElement = currentElement.offsetParent as HTMLElement|null));\n\n    return offset;\n  }\n\n  public static validateEmail(email: string): boolean {\n    return /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/.test(email);\n  }\n\n  public static validatePassword(password: string): boolean {\n    // return /(?=.{6,})(?=.*?[^\\w\\s])(?=.*?[0-9])(?=.*?[A-Z])(?=.*?[a-z]).*/.test(password);\n    // return /(?=.{8,})(?=.*?[A-Z])(?=.*?[a-z]).*/.test(password); // 8 characters, at least one uppercase\n    return /(?=.{8,})(?=.*?[A-Z]).*/.test(password); // 8 characters, at least one uppercase\n  }\n\n  public static wait(timeout: number = 20): Promise<void> {\n    return new Promise((res) => {\n      setTimeout(() => { res(); }, timeout);\n    });\n  }\n\n  public static asyncFunctionInTimeoutWrapper(funktion: () => Promise<void>, timeout = 20, thisContext: any = this): Promise<void> {\n    return new Promise((res, rej) => {\n      setTimeout(() => {\n        void funktion.apply(thisContext)\n          .then(() => {\n            res();\n          }, (reason) => {\n            rej(reason);\n          });\n      }, timeout);\n    });\n  }\n\n  public static debounceFunction(funktion: Function, debounceTime: number): IUtilsDebouncedFunction {\n    const f: IUtilsDebouncedFunction = function() {\n      if(f._timeout) {\n        clearTimeout(f._timeout);\n      }\n      f._lastArguments = arguments;\n      f._timeout = window.setTimeout(() => {\n        funktion.apply(funktion, f._lastArguments);\n      }, debounceTime);\n    };\n\n    f._timeout = null;\n    f._lastArguments = [];\n\n    return f;\n  }\n\n  /**\n   * prevents the function `f` to be called multiple times in the `rateInterval`\n   * each function call in the rateInterval will be combined to a single call\n   */\n  public static rateLimitFunction(func: Function, rateInterval: number): IUtilsRateLimitedFunction {\n    const f: IUtilsRateLimitedFunction = function() {\n      f._lastArguments = arguments;\n\n      if(!f._timeout) {\n        f._timeout = window.setTimeout(() => {\n          f._timeout = null;\n          func.apply(window, f._lastArguments);\n          f._lastArguments = [];\n        }, rateInterval);\n      }\n    };\n\n    f._timeout = null;\n    f._lastArguments = [];\n\n    f.cancel = function() {\n      if(f._timeout) {\n        clearTimeout(f._timeout);\n      }\n      f._timeout = null;\n    };\n\n    f.isPending = function() {\n      return !!f._timeout;\n    };\n\n    return f;\n  }\n\n  /**\n   * moves an item in an array to a new index, mutates the array\n   */\n  public static moveInArray(arr: Array<any>, oldIndex: number, newIndex: number): Array<any> {\n    while(oldIndex < 0) {\n      oldIndex += arr.length;\n    }\n    while(newIndex < 0) {\n      newIndex += arr.length;\n    }\n    if(newIndex >= arr.length) {\n      let k = newIndex - arr.length;\n      while((k--) + 1) {\n        arr.push(undefined);\n      }\n    }\n    arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]);\n    return arr;\n  }\n\n  /**\n   * limits the number of items in an array, cuts off at the beginning\n   */\n  public static limitArrayToNumberOfLastItems<T>(array: Array<T>, maxNumberOfItems: number): Array<T> {\n    let deletedItems: Array<T> = [];\n    const arrayLength = array.length;\n    if(arrayLength > maxNumberOfItems) {\n      deletedItems = array.splice(0, arrayLength - maxNumberOfItems);\n    }\n    return deletedItems;\n  }\n\n  public static b64toBlob(b64Data: string, contentType?: string, sliceSize?: number): Blob {\n    contentType = contentType || '';\n    sliceSize = sliceSize || 512;\n\n    const byteCharacters = atob(b64Data.replace(/^data:(.+)?;base64,/, ''));\n    const byteArrays = [];\n\n    for(let offset = 0; offset < byteCharacters.length; offset += sliceSize) {\n      const slice = byteCharacters.slice(offset, offset + sliceSize);\n\n      const byteNumbers = new Array(slice.length);\n      for(let i = 0; i < slice.length; i++) {\n        byteNumbers[i] = slice.charCodeAt(i);\n      }\n\n      byteArrays.push(new Uint8Array(byteNumbers));\n    }\n\n    return new Blob(byteArrays, { type: contentType });\n  }\n\n  /**\n   * joins args into 1 string and adds a / if necessary\n   */\n  public static joinPaths(...args: Array<string>): string {\n    let p = '';\n\n    for(let i = 0; i < args.length; i++) {\n      p += args[i];\n      if(args[i + 1] && args[i + 1][0] !== '/') {\n        if(args[i][args[i].length - 1] !== '/') p += '/';\n      }\n    }\n\n    return p;\n  }\n\n  public static getExtensionFromPath(path: string): string|null {\n    const res = /[^\\\\\\/]\\.([^.]+)$/.exec(path);\n    return res ? res[1] : null;\n  }\n\n  public static getViewModelOfElement<T>(element: HTMLElement): T|null {\n    const e = element as any;\n    return (e.au && e.au.controller) ? e.au.controller.viewModel : null;\n  }\n\n  public static parseNumberWithUnit(str: string): { value: number, unit: string }|null {\n    const res = /(-?(?:\\d+(?:\\.\\d*)?)|(?:\\.\\d+))(.*)/.exec(str);\n\n    if(res != null) {\n      return {\n        value: parseFloat(res[1]),\n        unit: res[2]\n      };\n    } else {\n      return null;\n    }\n  }\n\n  /**\n   * compares if both routes mean the same,\n   * e.g. #/project/123 is equal to /project/123\n   */\n  public static compareRoutes(route1: string|null, route2: string|null): boolean {\n    return this.trimRoute(route1) === this.trimRoute(route2);\n  }\n\n  /**\n   * e.g. #/project/123 will return /project/123\n   */\n  public static trimRoute(route: string|null): string|null {\n    if(route && route[0] === '#') { // currentRouteFragment has no leading '#'\n      return route.substr(1);\n    } else {\n      return route;\n    }\n  }\n\n  public static getClassNameForObject(object: Object): string {\n    const defaultClassName = 'UnknownClass';\n\n    if(object.constructor) {\n      const res = /function ([^(]*)\\(/.exec(object.constructor.toString());\n      return res && res[1] ? res[1] : defaultClassName;\n    } else {\n      return defaultClassName;\n    }\n  }\n\n  public static extractIdFromPictureFileName(pictureFileName: string): string|void {\n    const pictureFileNameSplit = pictureFileName.split(/^[^_]*_([^.]*)/);\n    if(pictureFileNameSplit.length < 2) return;\n    return pictureFileNameSplit[1];\n  }\n\n  public static deepFreeze(object: Record<string, any>): void {\n    // Retrieve the property names defined on object\n    const propNames = Object.getOwnPropertyNames(object);\n\n    // Freeze properties before freezing self\n    for(const name of propNames) {\n      const value = object[name];\n      if(value && typeof value === 'object') this.deepFreeze(value);\n    }\n\n    Object.freeze(object);\n  }\n\n  public static pickByKeys(object: Record<string, any>, keys: Array<string>): Record<string, any> {\n    return keys.reduce((obj, key) => {\n      if(object && object.hasOwnProperty(key)) {\n        obj[key] = object[key];\n      }\n      return obj;\n    }, {} as Record<string, any>);\n  }\n\n  public static walkThroughParentElements(element: Element|null, callback: (element: Element) => boolean): void {\n    let currentElement = element;\n    while(currentElement && !(currentElement instanceof HTMLDocument) && callback(currentElement)) {\n      currentElement = currentElement.parentElement;\n    }\n  }\n\n  public static groupBy<T, K>(values: Array<T>, keyGetter: (value: T) => K): Map<K, Array<T>> {\n    const map: Map<K, Array<T>> = new Map();\n\n    for(const value of values) {\n      const key = keyGetter(value);\n\n      const group = map.get(key);\n      if(group) {\n        group.push(value);\n      } else {\n        map.set(key, [value]);\n      }\n    }\n\n    return map;\n  }\n\n}\n\nexport interface IUtilsDebouncedFunction {\n  (...args: Array<any>): void;\n  _timeout: number|null;\n  _lastArguments: IArguments|Array<any>|null;\n}\n\nexport interface IUtilsRateLimitedFunction {\n  (...args: Array<any>): void;\n\n  /* cancels the pending func call */\n  cancel: Function;\n  isPending: () => boolean;\n\n  _timeout: number|null;\n  _lastArguments: IArguments|Array<any>|null;\n}\n","import { computedFrom } from 'aurelia-binding';\nimport { autoinject } from 'aurelia-dependency-injection';\nimport { PLATFORM, useView } from 'aurelia-framework';\nimport { bindable } from 'aurelia-templating';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./dropdown-select-label.html'))\nexport class DropdownSelectLabel<T extends Record<string, unknown>> {\n  @bindable() public selectItem: T | null = null;\n  @bindable() public propertyName: keyof T | null = null;\n  @bindable() public propertyNameTk: string | null = null;\n  @bindable() public fallbackTk: string | null = null;\n  @bindable() public params: Record<string, any> = {};\n\n  @computedFrom('propertyNameTk', 'selectItem')\n  private get usePropertyNameTk(): boolean {\n    return this.propertyNameTk != null\n      && !!this.selectItem?.[this.propertyNameTk];\n  }\n\n  @computedFrom('usePropertyNameTk', 'propertyName', 'selectItem')\n  private get usePropertyName(): boolean {\n    return !this.usePropertyNameTk\n      && this.propertyName != null\n      && !!this.selectItem?.[this.propertyName];\n  }\n\n  @computedFrom('usePropertyNameTk', 'usePropertyName')\n  private get useFallbackTk(): boolean {\n    return !this.usePropertyNameTk && !this.usePropertyName;\n  }\n}\n","import { MDCFloatingLabel } from '@material/floating-label';\nimport { MDCNotchedOutline } from '@material/notched-outline';\nimport { MDCSelect, MDCSelectEvent } from '@material/select';\nimport { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { IdGeneratorService } from 'common/aurelia-services/IdGeneratorService';\nimport { SubscriptionManager, SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { DomUtils } from 'common/utils/DomUtils';\n\nenum AllowedSelectStyles {\n  DistinarFilled = 'distinar-filled',\n  FormInput = 'form-input',\n  Outlined = 'outlined',\n  OutlinedInverted = 'outlined-inverted',\n  NoOutline = 'no-outline',\n}\nenum AllowedSelectSizes {\n  Small = 'small',\n  Medium = 'medium',\n  MediumBoxSmallText = 'medium-box-small-text'\n}\n\n/**\n * @event {SelectedItemChangedEvent} selected-item-changed\n * @event {DropdownFocusedEvent} dropdown-focused\n */\n\n@autoinject()\n@useView(PLATFORM.moduleName('./dropdown-select.html'))\nexport class DropdownSelect<T extends Record<string, unknown>> {\n  @bindable() public selectItems: T[] | null = null;\n  @bindable() public selectedItem: T | null = null;\n  @bindable() public labelPropertyName: keyof T | null = null;\n  @bindable() public labelPropertyNameTk: string | null = null;\n  @bindable() public valuePropertyName: keyof T | null = null;\n  /**\n   * provides an `index` parameter to passed tks\n   */\n  @bindable() public labelFallbackTk: string | null = null;\n  @bindable() public selectStyle: AllowedSelectStyles | null = null;\n  @bindable() public selectSize: AllowedSelectSizes | null = null;\n  @bindable() public fixedMenu = false;\n  @bindable() public autoMenu = false;\n  @bindable() public disabled: boolean | null = false;\n  @bindable() public outlineLabel: string | null = null;\n  @bindable() public error = false;\n  /**\n   * displayed if `selectItems.length` is `0`\n   */\n  @bindable() public noSelectionTk: string | null = null;\n  @bindable() public required = false;\n\n  private domElement: HTMLElement;\n  private dropdownLabelElement: HTMLElement | null = null;\n  private dropdownOutlineElement: HTMLElement | null = null;\n  private dropdownAnchorElement: HTMLElement | null = null;\n  private dropdownMenuElement: HTMLElement | null = null;\n  private select: MDCSelect | null = null;\n  private floatingLabel: MDCFloatingLabel | null = null;\n  private notchedOutline: MDCNotchedOutline | null = null;\n  private id: string;\n\n  private subscriptionManager: SubscriptionManager;\n\n  constructor(\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n    idGenerator: IdGeneratorService,\n  ) {\n    this.domElement = element as HTMLElement;\n    this.id = idGenerator.getId().toString();\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n  }\n\n  protected attached(): void {\n    assertNotNullOrUndefined(this.dropdownLabelElement, 'can\\'t create floatingLabel without dropdownLabelElement');\n    assertNotNullOrUndefined(this.dropdownOutlineElement, 'can\\'t create notchedOutline without dropdownOutlineElement');\n\n    this.select = new MDCSelect(this.domElement);\n    this.floatingLabel = new MDCFloatingLabel(this.dropdownLabelElement);\n    this.notchedOutline = new MDCNotchedOutline(this.dropdownOutlineElement);\n\n    this.subscriptionManager.subscribeToElementResize(this.domElement, () => {\n      this.removeLabelNotchBug();\n      this.matchFixedMenuWidthToAnchor();\n    });\n\n    this.select.listen('MDCSelect:change', (ev: MDCSelectEvent) => {\n      if(this.selectItems && this.select && this.valuePropertyName && ev.detail.index >= 0) {\n        DomUtils.fireEvent(this.domElement, {\n          name: 'selected-item-changed',\n          detail: {\n            selectedItem: this.selectItems[ev.detail.index]?.[this.valuePropertyName],\n          },\n        });\n      }\n    });\n\n    this.requiredChanged();\n  }\n\n  protected detached(): void {\n    this.subscriptionManager.disposeSubscriptions();\n    this.select?.destroy();\n    this.floatingLabel?.destroy();\n    this.notchedOutline?.destroy();\n  }\n\n  private selectedItemChanged(): void {\n    const { valuePropertyName } = this;\n    if(!this.select || !valuePropertyName || !this.selectItems) return;\n    const selectedIndex = this.selectItems.findIndex(i => i[valuePropertyName] === this.selectedItem?.[valuePropertyName]);\n    if(selectedIndex !== -1) {\n      this.select.selectedIndex = selectedIndex;\n    }\n    this.removeLabelNotchBug();\n  }\n\n  private outlineLabelChanged(): void {\n    this.removeLabelNotchBug();\n  }\n\n  private requiredChanged(): void {\n    if(this.select) {\n      this.select.required = this.required;\n      this.removeLabelNotchBug();\n    }\n  }\n\n  private removeLabelNotchBug(): void {\n    if(!this.selectedItem || !this.notchedOutline || !this.outlineLabel) return;\n    this.notchedOutline.notch(DomUtils.getLabelTextWidth(this.outlineLabel, this.required)); // fit outline-notch to prefilled label\n  }\n\n  private dropdownFocused(): void {\n    DomUtils.fireEvent(this.domElement, { name: 'dropdown-focused', bubbles: false });\n  }\n\n  private matchFixedMenuWidthToAnchor(): void {\n    if(!this.dropdownMenuElement || !this.dropdownAnchorElement) return;\n    if(this.fixedMenu) {\n      this.dropdownMenuElement.style.width = `${this.dropdownAnchorElement.clientWidth}px`;\n    } else {\n      this.dropdownMenuElement.style.width = '';\n    }\n  }\n}\n\nexport type SelectedItemChangedEvent<T> = Event & { detail: { selectedItem: T } };\nexport type DropdownFocusedEvent = CustomEvent<never>;\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/dropdown-select/dropdown-select'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/dropdown-select/dropdown-select-label'));\n}\n"],"names":[],"sourceRoot":""}