{"version":3,"sources":["vendor/ember-cli/app-prefix.js","m08-2020/ThreeCSG.js","m08-2020/adapters/-json-api.js","m08-2020/adapters/application.js","m08-2020/adapters/projektdaten.js","m08-2020/adapters/x3ddefault.js","m08-2020/app.js","m08-2020/cldrs/en.js","m08-2020/component-managers/glimmer.js","m08-2020/components/ember-jstree.js","m08-2020/components/file-dropzone.js","m08-2020/components/file-picker.js","m08-2020/components/file-upload.js","m08-2020/components/welcome-page.js","m08-2020/components/x-tree-branch.js","m08-2020/components/x-tree-checkbox.js","m08-2020/components/x-tree-children.js","m08-2020/components/x-tree-collapsed-icon.js","m08-2020/components/x-tree-expanded-icon.js","m08-2020/components/x-tree-node.js","m08-2020/components/x-tree-toggle.js","m08-2020/components/x-tree.js","m08-2020/controllers/application.js","m08-2020/data-adapter.js","m08-2020/formats.js","m08-2020/helpers/app-version.js","m08-2020/helpers/file-queue.js","m08-2020/helpers/format-date.js","m08-2020/helpers/format-message.js","m08-2020/helpers/format-number.js","m08-2020/helpers/format-relative.js","m08-2020/helpers/format-time.js","m08-2020/helpers/pluralize.js","m08-2020/helpers/send.js","m08-2020/helpers/singularize.js","m08-2020/helpers/t.js","m08-2020/initializers/app-version.js","m08-2020/initializers/container-debug-adapter.js","m08-2020/initializers/ember-data-data-adapter.js","m08-2020/initializers/ember-data.js","m08-2020/initializers/export-application-global.js","m08-2020/initializers/model-locale.js","m08-2020/instance-initializers/ember-data.js","m08-2020/lib/CSGMesh.js","m08-2020/lib/ClippingUtils/DynamicSectionalPlane.js","m08-2020/lib/ClippingUtils/OutlineGenerator.js","m08-2020/lib/ClippingUtils/SectionalPlane.js","m08-2020/lib/DXFGenerator.js","m08-2020/lib/FigureLoaders/ArrowLoader.js","m08-2020/lib/FigureLoaders/DimensionalChainLoader.js","m08-2020/lib/FigureLoaders/DrawingObjectComponents/ComplexVolume.js","m08-2020/lib/FigureLoaders/DrawingObjectComponents/Ellipse.js","m08-2020/lib/FigureLoaders/DrawingObjectComponents/Ellipsoid.js","m08-2020/lib/FigureLoaders/DrawingObjectComponents/Point.js","m08-2020/lib/FigureLoaders/DrawingObjectComponents/Polygon.js","m08-2020/lib/FigureLoaders/DrawingObjectComponents/Polyline.js","m08-2020/lib/FigureLoaders/DrawingObjectLoader.js","m08-2020/lib/FigureLoaders/DrawingPlaneLoader.js","m08-2020/lib/FigureLoaders/FastenerLoader.js","m08-2020/lib/OutlinesGeometry.js","m08-2020/lib/SectionalPlane.js","m08-2020/lib/ThreeCSG.js","m08-2020/lib/ThreeExtensions/CustomEllipseCurve.js","m08-2020/lib/ThreeExtensions/OutlinesGeometry.js","m08-2020/lib/ThreeExtensions/PlanarExtrusionPointsGenerator.js","m08-2020/lib/ThreeExtensions/PlanarRotationPointsGenerator.js","m08-2020/lib/ThreeExtensions/RotatedGeometry.js","m08-2020/lib/ThreeModule.js","m08-2020/lib/Utils.js","m08-2020/lib/Utils/BooleanOperations.js","m08-2020/lib/Utils/DimensionalChainIntersectionDetection.js","m08-2020/lib/Utils/LineIntersectionDetection.js","m08-2020/lib/Utils/PointInsidePolygonCheck2D.js","m08-2020/lib/WireframeGenerator.js","m08-2020/lib/ZoomController.js","m08-2020/lib/dxf_colors.js","m08-2020/mixins/model-validator.js","m08-2020/mixins/object-validator.js","m08-2020/models/application.js","m08-2020/models/position.js","m08-2020/models/rotation.js","m08-2020/router.js","m08-2020/routes/application.js","m08-2020/serializers/-default.js","m08-2020/serializers/-json-api.js","m08-2020/serializers/-rest.js","m08-2020/services/file-queue.js","m08-2020/services/intl.js","m08-2020/services/store.js","m08-2020/templates/application.js","m08-2020/templates/components/custom-input.js","m08-2020/templates/components/file-picker.js","m08-2020/transforms/boolean.js","m08-2020/transforms/date.js","m08-2020/transforms/number.js","m08-2020/transforms/string.js","m08-2020/translations/en-us.js","m08-2020/utils/intl/missing-message.js","vendor/ember-cli/app-suffix.js","vendor/ember-cli/app-config.js","vendor/ember-cli/app-boot.js"],"sourcesContent":["'use strict';\n\n\n","define(\"m08-2020/ThreeCSG\", [], function () {\n  'use strict';\n\n  window.ThreeBSP = function () {\n    var ThreeBSP,\n        EPSILON = 1e-5,\n        COPLANAR = 0,\n        FRONT = 1,\n        BACK = 2,\n        SPANNING = 3;\n\n    ThreeBSP = function (geometry) {\n      // Convert THREE.Geometry to ThreeBSP\n      var i,\n          _length_i,\n          face,\n          vertex,\n          faceVertexUvs,\n          polygon,\n          polygons = [],\n          tree;\n\n      if (geometry instanceof THREE.Geometry) {\n        this.matrix = new THREE.Matrix4();\n      } else if (geometry instanceof THREE.Mesh) {\n        // #todo: add hierarchy support \n        geometry.updateMatrix();\n        this.matrix = geometry.matrixWorld.clone(); // Lee was here -- changed matrix to matrixWorld\n\n        geometry = geometry.geometry;\n      } else if (geometry instanceof ThreeBSP.Node) {\n        this.tree = geometry;\n        this.matrix = new THREE.Matrix4();\n        return this;\n      } else {\n        throw 'ThreeBSP: Given geometry is unsupported';\n      }\n\n      for (i = 0, _length_i = geometry.faces.length; i < _length_i; i++) {\n        face = geometry.faces[i];\n        faceVertexUvs = geometry.faceVertexUvs[0][i];\n        polygon = new ThreeBSP.Polygon();\n\n        if (face instanceof THREE.Face3) {\n          vertex = geometry.vertices[face.a];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[0].u, faceVertexUvs[0].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.b];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[1], new THREE.Vector2(faceVertexUvs[1].u, faceVertexUvs[1].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.c];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[2], new THREE.Vector2(faceVertexUvs[2].u, faceVertexUvs[2].v));\n          polygon.vertices.push(vertex);\n        } else if (typeof THREE.Face4) {\n          vertex = geometry.vertices[face.a];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[0].u, faceVertexUvs[0].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.b];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[1], new THREE.Vector2(faceVertexUvs[1].u, faceVertexUvs[1].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.c];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[2], new THREE.Vector2(faceVertexUvs[2].u, faceVertexUvs[2].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.d];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[3], new THREE.Vector2(faceVertexUvs[3].u, faceVertexUvs[3].v));\n          polygon.vertices.push(vertex);\n        } else {\n          throw 'Invalid face type at index ' + i;\n        }\n\n        polygon.calculateProperties();\n        polygons.push(polygon);\n      }\n\n      ;\n      this.tree = new ThreeBSP.Node(polygons);\n    };\n\n    ThreeBSP.prototype.subtract = function (other_tree) {\n      var a = this.tree.clone(),\n          b = other_tree.tree.clone();\n      a.invert();\n      a.clipTo(b);\n      b.clipTo(a);\n      b.invert();\n      b.clipTo(a);\n      b.invert();\n      a.build(b.allPolygons());\n      a.invert();\n      a = new ThreeBSP(a);\n      a.matrix = this.matrix;\n      return a;\n    };\n\n    ThreeBSP.prototype.union = function (other_tree) {\n      var a = this.tree.clone(),\n          b = other_tree.tree.clone();\n      a.clipTo(b);\n      b.clipTo(a);\n      b.invert();\n      b.clipTo(a);\n      b.invert();\n      a.build(b.allPolygons());\n      a = new ThreeBSP(a);\n      a.matrix = this.matrix;\n      return a;\n    };\n\n    ThreeBSP.prototype.intersect = function (other_tree) {\n      var a = this.tree.clone(),\n          b = other_tree.tree.clone();\n      a.invert();\n      b.clipTo(a);\n      b.invert();\n      a.clipTo(b);\n      b.clipTo(a);\n      a.build(b.allPolygons());\n      a.invert();\n      a = new ThreeBSP(a);\n      a.matrix = this.matrix;\n      return a;\n    };\n\n    ThreeBSP.prototype.toGeometry = function () {\n      var i,\n          j,\n          matrix = new THREE.Matrix4().getInverse(this.matrix),\n          geometry = new THREE.Geometry(),\n          polygons = this.tree.allPolygons(),\n          polygon_count = polygons.length,\n          polygon,\n          polygon_vertice_count,\n          vertice_dict = {},\n          vertex_idx_a,\n          vertex_idx_b,\n          vertex_idx_c,\n          vertex,\n          face,\n          verticeNormals,\n          verticeUvs;\n\n      for (i = 0; i < polygon_count; i++) {\n        polygon = polygons[i];\n        polygon_vertice_count = polygon.vertices.length;\n\n        for (j = 2; j < polygon_vertice_count; j++) {\n          verticeNormals = [];\n          verticeUvs = [];\n          vertex = polygon.vertices[0];\n          verticeNormals.push(vertex.normal);\n          verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));\n          vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);\n          vertex.applyMatrix4(matrix);\n\n          if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined') {\n            vertex_idx_a = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];\n          } else {\n            geometry.vertices.push(vertex);\n            vertex_idx_a = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;\n          }\n\n          vertex = polygon.vertices[j - 1];\n          verticeNormals.push(vertex.normal);\n          verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));\n          vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);\n          vertex.applyMatrix4(matrix);\n\n          if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined') {\n            vertex_idx_b = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];\n          } else {\n            geometry.vertices.push(vertex);\n            vertex_idx_b = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;\n          }\n\n          vertex = polygon.vertices[j];\n          verticeNormals.push(vertex.normal);\n          verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));\n          vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);\n          vertex.applyMatrix4(matrix);\n\n          if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined') {\n            vertex_idx_c = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];\n          } else {\n            geometry.vertices.push(vertex);\n            vertex_idx_c = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;\n          }\n\n          face = new THREE.Face3(vertex_idx_a, vertex_idx_b, vertex_idx_c, new THREE.Vector3(polygon.normal.x, polygon.normal.y, polygon.normal.z));\n          face.vertexNormals.push(verticeNormals[0], verticeNormals[1], verticeNormals[2]);\n          geometry.faces.push(face);\n          geometry.faceVertexUvs[0].push(verticeUvs);\n        }\n      }\n\n      return geometry;\n    };\n\n    ThreeBSP.prototype.toMesh = function (material) {\n      var geometry = this.toGeometry(),\n          mesh = new THREE.Mesh(geometry, material);\n      mesh.position.getPositionFromMatrix(this.matrix); //mesh.rotation.setEulerFromRotationMatrix( this.matrix );//not working and commented\n\n      mesh.position.setFromMatrixPosition(this.matrix); //from stackoverflow (https://stackoverflow.com/questions/17711914/seteulerfromrotationmatrix-does-not-exist-in-three-js)\n\n      return mesh;\n    };\n\n    ThreeBSP.Polygon = function (vertices, normal, w) {\n      if (!(vertices instanceof Array)) {\n        vertices = [];\n      }\n\n      this.vertices = vertices;\n\n      if (vertices.length > 0) {\n        this.calculateProperties();\n      } else {\n        this.normal = this.w = undefined;\n      }\n    };\n\n    ThreeBSP.Polygon.prototype.calculateProperties = function () {\n      var a = this.vertices[0],\n          b = this.vertices[1],\n          c = this.vertices[2];\n      this.normal = b.clone().subtract(a).cross(c.clone().subtract(a)).normalize();\n      this.w = this.normal.clone().dot(a);\n      return this;\n    };\n\n    ThreeBSP.Polygon.prototype.clone = function () {\n      var i,\n          vertice_count,\n          polygon = new ThreeBSP.Polygon();\n\n      for (i = 0, vertice_count = this.vertices.length; i < vertice_count; i++) {\n        polygon.vertices.push(this.vertices[i].clone());\n      }\n\n      ;\n      polygon.calculateProperties();\n      return polygon;\n    };\n\n    ThreeBSP.Polygon.prototype.flip = function () {\n      var i,\n          vertices = [];\n      this.normal.multiplyScalar(-1);\n      this.w *= -1;\n\n      for (i = this.vertices.length - 1; i >= 0; i--) {\n        //this.vertices[i].normal.multiplyScalar( -1 );\n        vertices.push(this.vertices[i]);\n      }\n\n      ;\n      this.vertices = vertices;\n      return this;\n    };\n\n    ThreeBSP.Polygon.prototype.classifyVertex = function (vertex) {\n      var side_value = this.normal.dot(vertex) - this.w;\n\n      if (side_value < -EPSILON) {\n        return BACK;\n      } else if (side_value > EPSILON) {\n        return FRONT;\n      } else {\n        return COPLANAR;\n      }\n    };\n\n    ThreeBSP.Polygon.prototype.classifySide = function (polygon) {\n      var i,\n          vertex,\n          classification,\n          num_positive = 0,\n          num_negative = 0,\n          vertice_count = polygon.vertices.length;\n\n      for (i = 0; i < vertice_count; i++) {\n        vertex = polygon.vertices[i];\n        classification = this.classifyVertex(vertex);\n\n        if (classification === FRONT) {\n          num_positive++;\n        } else if (classification === BACK) {\n          num_negative++;\n        }\n      }\n\n      if (num_positive > 0 && num_negative === 0) {\n        return FRONT;\n      } else if (num_positive === 0 && num_negative > 0) {\n        return BACK;\n      } else if (num_positive === 0 && num_negative === 0) {\n        return COPLANAR;\n      } else {\n        return SPANNING;\n      }\n    };\n\n    ThreeBSP.Polygon.prototype.splitPolygon = function (polygon, coplanar_front, coplanar_back, front, back) {\n      var classification = this.classifySide(polygon);\n\n      if (classification === COPLANAR) {\n        (this.normal.dot(polygon.normal) > 0 ? coplanar_front : coplanar_back).push(polygon);\n      } else if (classification === FRONT) {\n        front.push(polygon);\n      } else if (classification === BACK) {\n        back.push(polygon);\n      } else {\n        var vertice_count,\n            i,\n            j,\n            ti,\n            tj,\n            vi,\n            vj,\n            t,\n            v,\n            f = [],\n            b = [];\n\n        for (i = 0, vertice_count = polygon.vertices.length; i < vertice_count; i++) {\n          j = (i + 1) % vertice_count;\n          vi = polygon.vertices[i];\n          vj = polygon.vertices[j];\n          ti = this.classifyVertex(vi);\n          tj = this.classifyVertex(vj);\n          if (ti != BACK) f.push(vi);\n          if (ti != FRONT) b.push(vi);\n\n          if ((ti | tj) === SPANNING) {\n            t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().subtract(vi));\n            v = vi.interpolate(vj, t);\n            f.push(v);\n            b.push(v);\n          }\n        }\n\n        if (f.length >= 3) front.push(new ThreeBSP.Polygon(f).calculateProperties());\n        if (b.length >= 3) back.push(new ThreeBSP.Polygon(b).calculateProperties());\n      }\n    };\n\n    ThreeBSP.Vertex = function (x, y, z, normal, uv) {\n      this.x = x;\n      this.y = y;\n      this.z = z;\n      this.normal = normal || new THREE.Vector3();\n      this.uv = uv || new THREE.Vector2();\n    };\n\n    ThreeBSP.Vertex.prototype.clone = function () {\n      return new ThreeBSP.Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone());\n    };\n\n    ThreeBSP.Vertex.prototype.add = function (vertex) {\n      this.x += vertex.x;\n      this.y += vertex.y;\n      this.z += vertex.z;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.subtract = function (vertex) {\n      this.x -= vertex.x;\n      this.y -= vertex.y;\n      this.z -= vertex.z;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.multiplyScalar = function (scalar) {\n      this.x *= scalar;\n      this.y *= scalar;\n      this.z *= scalar;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.cross = function (vertex) {\n      var x = this.x,\n          y = this.y,\n          z = this.z;\n      this.x = y * vertex.z - z * vertex.y;\n      this.y = z * vertex.x - x * vertex.z;\n      this.z = x * vertex.y - y * vertex.x;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.normalize = function () {\n      var length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\n      this.x /= length;\n      this.y /= length;\n      this.z /= length;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.dot = function (vertex) {\n      return this.x * vertex.x + this.y * vertex.y + this.z * vertex.z;\n    };\n\n    ThreeBSP.Vertex.prototype.lerp = function (a, t) {\n      this.add(a.clone().subtract(this).multiplyScalar(t));\n      this.normal.add(a.normal.clone().sub(this.normal).multiplyScalar(t));\n      this.uv.add(a.uv.clone().sub(this.uv).multiplyScalar(t));\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.interpolate = function (other, t) {\n      return this.clone().lerp(other, t);\n    };\n\n    ThreeBSP.Node = function (polygons) {\n      var i,\n          polygon_count,\n          front = [],\n          back = [];\n      this.polygons = [];\n      this.front = this.back = undefined;\n      if (!(polygons instanceof Array) || polygons.length === 0) return;\n      this.divider = polygons[0].clone();\n\n      for (i = 0, polygon_count = polygons.length; i < polygon_count; i++) {\n        this.divider.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);\n      }\n\n      if (front.length > 0) {\n        this.front = new ThreeBSP.Node(front);\n      }\n\n      if (back.length > 0) {\n        this.back = new ThreeBSP.Node(back);\n      }\n    };\n\n    ThreeBSP.Node.prototype.build = function (polygons) {\n      var i,\n          polygon_count,\n          front = [],\n          back = [];\n\n      if (!this.divider) {\n        this.divider = polygons[0].clone();\n      }\n\n      for (i = 0, polygon_count = polygons.length; i < polygon_count; i++) {\n        this.divider.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);\n      }\n\n      if (front.length > 0) {\n        if (!this.front) this.front = new ThreeBSP.Node();\n        this.front.build(front);\n      }\n\n      if (back.length > 0) {\n        if (!this.back) this.back = new ThreeBSP.Node();\n        this.back.build(back);\n      }\n    };\n\n    ThreeBSP.Node.prototype.allPolygons = function () {\n      var polygons = this.polygons.slice();\n      if (this.front) polygons = polygons.concat(this.front.allPolygons());\n      if (this.back) polygons = polygons.concat(this.back.allPolygons());\n      return polygons;\n    };\n\n    ThreeBSP.Node.prototype.clone = function () {\n      var node = new ThreeBSP.Node();\n      node.divider = this.divider.clone();\n      node.polygons = this.polygons.map(function (polygon) {\n        return polygon.clone();\n      });\n      node.front = this.front && this.front.clone();\n      node.back = this.back && this.back.clone();\n      return node;\n    };\n\n    ThreeBSP.Node.prototype.invert = function () {\n      var i, polygon_count, temp;\n\n      for (i = 0, polygon_count = this.polygons.length; i < polygon_count; i++) {\n        this.polygons[i].flip();\n      }\n\n      this.divider.flip();\n      if (this.front) this.front.invert();\n      if (this.back) this.back.invert();\n      temp = this.front;\n      this.front = this.back;\n      this.back = temp;\n      return this;\n    };\n\n    ThreeBSP.Node.prototype.clipPolygons = function (polygons) {\n      var i, polygon_count, front, back;\n      if (!this.divider) return polygons.slice();\n      front = [], back = [];\n\n      for (i = 0, polygon_count = polygons.length; i < polygon_count; i++) {\n        this.divider.splitPolygon(polygons[i], front, back, front, back); //if (window.debug) console.debug( front.length, back.length );\n      }\n\n      if (this.front) front = this.front.clipPolygons(front);\n      if (this.back) back = this.back.clipPolygons(back);else back = [];\n      return front.concat(back);\n    };\n\n    ThreeBSP.Node.prototype.clipTo = function (node) {\n      this.polygons = node.clipPolygons(this.polygons);\n      if (this.front) this.front.clipTo(node);\n      if (this.back) this.back.clipTo(node);\n    };\n\n    return ThreeBSP;\n  }();\n});","define(\"m08-2020/adapters/-json-api\", [\"exports\", \"@ember-data/adapter/json-api\"], function (_exports, _jsonApi) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _jsonApi.default;\n    }\n  });\n});","define(\"m08-2020/adapters/application\", [\"exports\", \"@ember-data/adapter/rest\"], function (_exports, _rest) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  class ApplicationAdapter extends _rest.default {}\n\n  _exports.default = ApplicationAdapter;\n});","define(\"m08-2020/adapters/projektdaten\", [\"exports\", \"@ember-data/adapter/rest\"], function (_exports, _rest) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  class ApplicationAdapter extends _rest.default {}\n\n  _exports.default = ApplicationAdapter;\n});","define(\"m08-2020/adapters/x3ddefault\", [\"exports\", \"@ember-data/adapter/rest\"], function (_exports, _rest) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  class ApplicationAdapter extends _rest.default {}\n\n  _exports.default = ApplicationAdapter;\n});","define(\"m08-2020/app\", [\"exports\", \"ember-resolver\", \"ember-load-initializers\", \"m08-2020/config/environment\"], function (_exports, _emberResolver, _emberLoadInitializers, _environment) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n  class App extends Ember.Application {\n    constructor(...args) {\n      super(...args);\n\n      _defineProperty(this, \"modulePrefix\", _environment.default.modulePrefix);\n\n      _defineProperty(this, \"podModulePrefix\", _environment.default.podModulePrefix);\n\n      _defineProperty(this, \"Resolver\", _emberResolver.default);\n    }\n\n  }\n\n  _exports.default = App;\n  (0, _emberLoadInitializers.default)(App, _environment.default.modulePrefix);\n});","define(\"m08-2020/cldrs/en\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  /*jslint eqeq: true*/\n  var _default = [{\n    \"locale\": \"en-US\",\n    \"parentLocale\": \"en\"\n  }, {\n    \"locale\": \"en\",\n    \"pluralRuleFunction\": function (n, ord) {\n      var s = String(n).split(\".\"),\n          v0 = !s[1],\n          t0 = Number(s[0]) == n,\n          n10 = t0 && s[0].slice(-1),\n          n100 = t0 && s[0].slice(-2);\n      if (ord) return n10 == 1 && n100 != 11 ? \"one\" : n10 == 2 && n100 != 12 ? \"two\" : n10 == 3 && n100 != 13 ? \"few\" : \"other\";\n      return n == 1 && v0 ? \"one\" : \"other\";\n    },\n    \"fields\": {\n      \"year\": {\n        \"displayName\": \"year\",\n        \"relative\": {\n          \"0\": \"this year\",\n          \"1\": \"next year\",\n          \"-1\": \"last year\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} year\",\n            \"other\": \"in {0} years\"\n          },\n          \"past\": {\n            \"one\": \"{0} year ago\",\n            \"other\": \"{0} years ago\"\n          }\n        }\n      },\n      \"year-short\": {\n        \"displayName\": \"yr.\",\n        \"relative\": {\n          \"0\": \"this yr.\",\n          \"1\": \"next yr.\",\n          \"-1\": \"last yr.\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} yr.\",\n            \"other\": \"in {0} yr.\"\n          },\n          \"past\": {\n            \"one\": \"{0} yr. ago\",\n            \"other\": \"{0} yr. ago\"\n          }\n        }\n      },\n      \"month\": {\n        \"displayName\": \"month\",\n        \"relative\": {\n          \"0\": \"this month\",\n          \"1\": \"next month\",\n          \"-1\": \"last month\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} month\",\n            \"other\": \"in {0} months\"\n          },\n          \"past\": {\n            \"one\": \"{0} month ago\",\n            \"other\": \"{0} months ago\"\n          }\n        }\n      },\n      \"month-short\": {\n        \"displayName\": \"mo.\",\n        \"relative\": {\n          \"0\": \"this mo.\",\n          \"1\": \"next mo.\",\n          \"-1\": \"last mo.\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} mo.\",\n            \"other\": \"in {0} mo.\"\n          },\n          \"past\": {\n            \"one\": \"{0} mo. ago\",\n            \"other\": \"{0} mo. ago\"\n          }\n        }\n      },\n      \"day\": {\n        \"displayName\": \"day\",\n        \"relative\": {\n          \"0\": \"today\",\n          \"1\": \"tomorrow\",\n          \"-1\": \"yesterday\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} day\",\n            \"other\": \"in {0} days\"\n          },\n          \"past\": {\n            \"one\": \"{0} day ago\",\n            \"other\": \"{0} days ago\"\n          }\n        }\n      },\n      \"day-short\": {\n        \"displayName\": \"day\",\n        \"relative\": {\n          \"0\": \"today\",\n          \"1\": \"tomorrow\",\n          \"-1\": \"yesterday\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} day\",\n            \"other\": \"in {0} days\"\n          },\n          \"past\": {\n            \"one\": \"{0} day ago\",\n            \"other\": \"{0} days ago\"\n          }\n        }\n      },\n      \"hour\": {\n        \"displayName\": \"hour\",\n        \"relative\": {\n          \"0\": \"this hour\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} hour\",\n            \"other\": \"in {0} hours\"\n          },\n          \"past\": {\n            \"one\": \"{0} hour ago\",\n            \"other\": \"{0} hours ago\"\n          }\n        }\n      },\n      \"hour-short\": {\n        \"displayName\": \"hr.\",\n        \"relative\": {\n          \"0\": \"this hour\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} hr.\",\n            \"other\": \"in {0} hr.\"\n          },\n          \"past\": {\n            \"one\": \"{0} hr. ago\",\n            \"other\": \"{0} hr. ago\"\n          }\n        }\n      },\n      \"minute\": {\n        \"displayName\": \"minute\",\n        \"relative\": {\n          \"0\": \"this minute\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} minute\",\n            \"other\": \"in {0} minutes\"\n          },\n          \"past\": {\n            \"one\": \"{0} minute ago\",\n            \"other\": \"{0} minutes ago\"\n          }\n        }\n      },\n      \"minute-short\": {\n        \"displayName\": \"min.\",\n        \"relative\": {\n          \"0\": \"this minute\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} min.\",\n            \"other\": \"in {0} min.\"\n          },\n          \"past\": {\n            \"one\": \"{0} min. ago\",\n            \"other\": \"{0} min. ago\"\n          }\n        }\n      },\n      \"second\": {\n        \"displayName\": \"second\",\n        \"relative\": {\n          \"0\": \"now\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} second\",\n            \"other\": \"in {0} seconds\"\n          },\n          \"past\": {\n            \"one\": \"{0} second ago\",\n            \"other\": \"{0} seconds ago\"\n          }\n        }\n      },\n      \"second-short\": {\n        \"displayName\": \"sec.\",\n        \"relative\": {\n          \"0\": \"now\"\n        },\n        \"relativeTime\": {\n          \"future\": {\n            \"one\": \"in {0} sec.\",\n            \"other\": \"in {0} sec.\"\n          },\n          \"past\": {\n            \"one\": \"{0} sec. ago\",\n            \"other\": \"{0} sec. ago\"\n          }\n        }\n      }\n    },\n    \"numbers\": {\n      \"decimal\": {\n        \"long\": [[1000, {\n          \"one\": [\"0 thousand\", 1],\n          \"other\": [\"0 thousand\", 1]\n        }], [10000, {\n          \"one\": [\"00 thousand\", 2],\n          \"other\": [\"00 thousand\", 2]\n        }], [100000, {\n          \"one\": [\"000 thousand\", 3],\n          \"other\": [\"000 thousand\", 3]\n        }], [1000000, {\n          \"one\": [\"0 million\", 1],\n          \"other\": [\"0 million\", 1]\n        }], [10000000, {\n          \"one\": [\"00 million\", 2],\n          \"other\": [\"00 million\", 2]\n        }], [100000000, {\n          \"one\": [\"000 million\", 3],\n          \"other\": [\"000 million\", 3]\n        }], [1000000000, {\n          \"one\": [\"0 billion\", 1],\n          \"other\": [\"0 billion\", 1]\n        }], [10000000000, {\n          \"one\": [\"00 billion\", 2],\n          \"other\": [\"00 billion\", 2]\n        }], [100000000000, {\n          \"one\": [\"000 billion\", 3],\n          \"other\": [\"000 billion\", 3]\n        }], [1000000000000, {\n          \"one\": [\"0 trillion\", 1],\n          \"other\": [\"0 trillion\", 1]\n        }], [10000000000000, {\n          \"one\": [\"00 trillion\", 2],\n          \"other\": [\"00 trillion\", 2]\n        }], [100000000000000, {\n          \"one\": [\"000 trillion\", 3],\n          \"other\": [\"000 trillion\", 3]\n        }]],\n        \"short\": [[1000, {\n          \"one\": [\"0K\", 1],\n          \"other\": [\"0K\", 1]\n        }], [10000, {\n          \"one\": [\"00K\", 2],\n          \"other\": [\"00K\", 2]\n        }], [100000, {\n          \"one\": [\"000K\", 3],\n          \"other\": [\"000K\", 3]\n        }], [1000000, {\n          \"one\": [\"0M\", 1],\n          \"other\": [\"0M\", 1]\n        }], [10000000, {\n          \"one\": [\"00M\", 2],\n          \"other\": [\"00M\", 2]\n        }], [100000000, {\n          \"one\": [\"000M\", 3],\n          \"other\": [\"000M\", 3]\n        }], [1000000000, {\n          \"one\": [\"0B\", 1],\n          \"other\": [\"0B\", 1]\n        }], [10000000000, {\n          \"one\": [\"00B\", 2],\n          \"other\": [\"00B\", 2]\n        }], [100000000000, {\n          \"one\": [\"000B\", 3],\n          \"other\": [\"000B\", 3]\n        }], [1000000000000, {\n          \"one\": [\"0T\", 1],\n          \"other\": [\"0T\", 1]\n        }], [10000000000000, {\n          \"one\": [\"00T\", 2],\n          \"other\": [\"00T\", 2]\n        }], [100000000000000, {\n          \"one\": [\"000T\", 3],\n          \"other\": [\"000T\", 3]\n        }]]\n      }\n    }\n  }];\n  _exports.default = _default;\n});","define(\"m08-2020/component-managers/glimmer\", [\"exports\", \"@glimmer/component/-private/ember-component-manager\"], function (_exports, _emberComponentManager) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _emberComponentManager.default;\n    }\n  });\n});","define(\"m08-2020/components/ember-jstree\", [\"exports\", \"ember-cli-jstree/components/ember-jstree\"], function (_exports, _emberJstree) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _emberJstree.default;\n    }\n  });\n});","define(\"m08-2020/components/file-dropzone\", [\"exports\", \"ember-file-upload/components/file-dropzone/component\"], function (_exports, _component) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _component.default;\n    }\n  });\n});","define(\"m08-2020/components/file-picker\", [\"exports\", \"ember-cli-file-picker/components/file-picker\"], function (_exports, _filePicker) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _filePicker.default;\n    }\n  });\n});","define(\"m08-2020/components/file-upload\", [\"exports\", \"ember-file-upload/components/file-upload/component\"], function (_exports, _component) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _component.default;\n    }\n  });\n});","define(\"m08-2020/components/welcome-page\", [\"exports\", \"ember-welcome-page/components/welcome-page\"], function (_exports, _welcomePage) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _welcomePage.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree-branch\", [\"exports\", \"ember-simple-tree/components/x-tree-branch\"], function (_exports, _xTreeBranch) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTreeBranch.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree-checkbox\", [\"exports\", \"ember-simple-tree/components/x-tree-checkbox\"], function (_exports, _xTreeCheckbox) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTreeCheckbox.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree-children\", [\"exports\", \"ember-simple-tree/components/x-tree-children\"], function (_exports, _xTreeChildren) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTreeChildren.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree-collapsed-icon\", [\"exports\", \"ember-simple-tree/components/x-tree-collapsed-icon\"], function (_exports, _xTreeCollapsedIcon) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTreeCollapsedIcon.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree-expanded-icon\", [\"exports\", \"ember-simple-tree/components/x-tree-expanded-icon\"], function (_exports, _xTreeExpandedIcon) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTreeExpandedIcon.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree-node\", [\"exports\", \"ember-simple-tree/components/x-tree-node\"], function (_exports, _xTreeNode) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTreeNode.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree-toggle\", [\"exports\", \"ember-simple-tree/components/x-tree-toggle\"], function (_exports, _xTreeToggle) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTreeToggle.default;\n    }\n  });\n});","define(\"m08-2020/components/x-tree\", [\"exports\", \"ember-simple-tree/components/x-tree\"], function (_exports, _xTree) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _xTree.default;\n    }\n  });\n});","define(\"m08-2020/controllers/application\", [\"exports\", \"three\", \"m08-2020/lib/ThreeModule\", \"jquery\", \"polybooljs\", \"@tweenjs/tween.js\"], function (_exports, THREE, _ThreeModule, _jquery, _polybooljs, _tween) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _dec11, _dec12, _dec13, _dec14, _dec15, _dec16, _obj;\n\n  function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object.keys(descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object.defineProperty(target, property, desc); desc = null; } return desc; }\n\n  //Schaltet die Deprication Warnungen aus\n  Ember.deprecate = function () {};\n\n  var _default = Ember.Controller.extend((_dec = Ember._action, _dec2 = Ember._action, _dec3 = Ember._action, _dec4 = Ember._action, _dec5 = Ember._action, _dec6 = Ember._action, _dec7 = Ember._action, _dec8 = Ember._action, _dec9 = Ember._action, _dec10 = Ember._action, _dec11 = Ember._action, _dec12 = Ember._action, _dec13 = Ember._action, _dec14 = Ember._action, _dec15 = Ember._action, _dec16 = Ember._action, (_obj = {\n    version: \"##version##\",\n    loggedIn: true,\n    wuerth: false,\n    swg: true,\n    verbaende: false,\n    intl: Ember.inject.service(),\n    appController: Ember.inject.controller('application'),\n    init: function () {\n      this._super();\n    },\n    initialisierung: function () {\n      var self = this;\n    },\n\n    loadAction() {\n      (0, _jquery.default)('#file-input').trigger('click');\n    },\n\n    async openFileAction(file) {\n      console.log(\"fileLoaded action \");\n      var self = this;\n      console.log(\"jetzt werden die werte gesetzt!\");\n      var content = JSON.parse(await this.getFileData(event));\n      console.log('filecontent'); // console.log(content);\n\n      console.log(content.drawingObjects); // console.log(content.drawingObjects.length);\n      //\n      // console.log(content.drawingObjects.findBy('id', \"ZO1\"));\n      // console.log(content.drawingObjects.arrows);\n\n      self.graphicsThree3D.clearScene();\n      self.graphicsThree3D.drawCustom(content); // self.graphicsThree3D.drawObject(content);\n      // self.graphicsThree3D.drawFastenerAsync();\n    },\n\n    getFileData: function (event) {\n      var self = this; // getting a hold of the file reference\n\n      var file = event.target.files[0];\n      console.log(\"Dateiname: \" + event.target.files[0].name); // setting up the reader\n\n      var reader = new FileReader();\n      reader.readAsText(file, 'UTF-8'); //return data string\n\n      return new Promise(resolve => {\n        reader.onload = readerEvent => {\n          resolve(readerEvent.target.result);\n        };\n      });\n    },\n    jsonUrl: 'example.json',\n    //common ember part\n    x: \"\",\n    y: \"\",\n    z: \"\",\n    placeholderX: \"x\",\n    placeholderY: \"y\",\n    placeholderZ: \"z\",\n    graphicsThree3D: null,\n\n    setXInteractive(variable, value) {\n      this.get('model').application.objectAt(0).set(variable, value);\n      var newX = Number(this.get('model').application.objectAt(0).get('x'));\n      if (!this.isNumeric(newX)) newX = null;\n      this.graphicsThree3D.highlightX(newX);\n    },\n\n    setYInteractive(variable, value) {\n      this.get('model').application.objectAt(0).set(variable, value);\n      var newY = Number(this.get('model').application.objectAt(0).get('y'));\n      if (!this.isNumeric(newY)) newY = null;\n      this.graphicsThree3D.highlightY(newY);\n    },\n\n    setZInteractive(variable, value) {\n      this.get('model').application.objectAt(0).set(variable, value); //this.cube.geometry = new THREE.BoxGeometry(Number(this.get('model').application.objectAt(0).get('x')), Number(this.get('model').application.objectAt(0).get('y')), Number(this.get('model').application.objectAt(0).get('z')));\n\n      var newZ = Number(this.get('model').application.objectAt(0).get('z'));\n      if (!this.isNumeric(newZ)) newZ = null;\n      this.graphicsThree3D.highlightZ(newZ); //   while(this.scene.children.length > 0){\n      //     this.scene.remove(this.scene.children[0]);\n      // }\n      // this.meshArray=[];\n      // this.xPosIndeX=0;\n      // this.xPosIndeY=0;\n      // //console.log(newZ);\n      // if(newZ)\n      // for (let i = 0; i < this.extrusionVectorZOfObjectsArray.length; i++) {\n      //   this.extrusionVectorZOfObjectsArray[i] = newZ;\n      // }\n      // //var isInteractiveZ=newZ?false:true;\n      //   this.AddShapesToScene(newZ,true);\n    },\n\n    clearXInteractive() {\n      this.graphicsThree3D.clearXHighlight();\n    },\n\n    clearYInteractive() {\n      this.graphicsThree3D.clearYHighlight();\n    },\n\n    clearZInteractive() {\n      this.graphicsThree3D.clearZHighlight();\n    },\n\n    isNumeric(n) {\n      return !isNaN(parseFloat(n)) && isFinite(n);\n    },\n\n    //get objects json and initialize three.js scene\n    threejsscene: Ember.computed('', function () {\n      const self = this;\n      self.graphicsThree3D = new _ThreeModule.GraphicsThree3D();\n      let returnValue = self.graphicsThree3D.getGraphicsCanvas(); // self.get('geometrieController').set3D(-1, { target: { name: \"initialization\" }});\n\n      self.getAllJsonWithAjax(self);\n      return returnValue;\n    }),\n\n    getAllJsonWithAjax(self) {\n      _jquery.default.ajax({\n        'async': false,\n        type: \"GET\",\n        url: self.jsonUrl\n      }).then(function (response) {\n        self.graphicsThree3D.globalJSONData = response;\n        self.graphicsThree3D.drawCustom(response); // let i = 1;\n        // setInterval(() => {\n        //   let count = `00${i}`.slice(-2);\n        //   console.log(count)\n        //   self.graphicsThree3D.clearScene();\n        //   let newResponse = `http://localhost:12345/Jsons/DoEx40_${count}_20210217.json`;\n        //   $.ajax({\n        //     'async': false,\n        //     type: \"GET\",\n        //     url: newResponse\n        //   }).then(function (response) {\n        //     self.graphicsThree3D.drawCustom(response);\n        //   }, function (error) {\n        //     console.log(error);\n        //   });\n        //   i++;\n        // }, 1000);\n      }, function (error) {\n        console.log(error);\n      });\n    },\n\n    ChangePosition0() {\n      this.graphicsThree3D.ChangeCameraPosition0();\n    },\n\n    ChangePosition1() {\n      this.graphicsThree3D.ChangeCameraPosition1();\n    },\n\n    ChangePosition2() {\n      this.graphicsThree3D.ChangeCameraPosition2();\n    },\n\n    ChangePosition3() {\n      this.graphicsThree3D.ChangeCameraPosition3();\n    },\n\n    ToggleWireframe() {\n      this.graphicsThree3D.ToggleWireframe();\n    },\n\n    loadDrawingPlanes() {\n      this.graphicsThree3D.DrawingPlaneLoader.loadDrawingPlanes();\n    },\n\n    loadDXF3D() {\n      this.graphicsThree3D.dxfGenerator.downloadDXF3D();\n    },\n\n    SendBase64PNGToServer() {\n      this.graphicsThree3D.SendBase64PNGToServer();\n    } // @action\n    // changecamerax(){\n    //   this.camera.position.x+=0.1;\n    //   this.controls.update();\n    // },\n    // @action\n    // changecameray(){\n    //   this.camera.position.y-=0.1;\n    //   this.controls.update();\n    // },\n\n\n  }, (_applyDecoratedDescriptor(_obj, \"loadAction\", [_dec], Object.getOwnPropertyDescriptor(_obj, \"loadAction\"), _obj), _applyDecoratedDescriptor(_obj, \"openFileAction\", [_dec2], Object.getOwnPropertyDescriptor(_obj, \"openFileAction\"), _obj), _applyDecoratedDescriptor(_obj, \"setXInteractive\", [_dec3], Object.getOwnPropertyDescriptor(_obj, \"setXInteractive\"), _obj), _applyDecoratedDescriptor(_obj, \"setYInteractive\", [_dec4], Object.getOwnPropertyDescriptor(_obj, \"setYInteractive\"), _obj), _applyDecoratedDescriptor(_obj, \"setZInteractive\", [_dec5], Object.getOwnPropertyDescriptor(_obj, \"setZInteractive\"), _obj), _applyDecoratedDescriptor(_obj, \"clearXInteractive\", [_dec6], Object.getOwnPropertyDescriptor(_obj, \"clearXInteractive\"), _obj), _applyDecoratedDescriptor(_obj, \"clearYInteractive\", [_dec7], Object.getOwnPropertyDescriptor(_obj, \"clearYInteractive\"), _obj), _applyDecoratedDescriptor(_obj, \"clearZInteractive\", [_dec8], Object.getOwnPropertyDescriptor(_obj, \"clearZInteractive\"), _obj), _applyDecoratedDescriptor(_obj, \"ChangePosition0\", [_dec9], Object.getOwnPropertyDescriptor(_obj, \"ChangePosition0\"), _obj), _applyDecoratedDescriptor(_obj, \"ChangePosition1\", [_dec10], Object.getOwnPropertyDescriptor(_obj, \"ChangePosition1\"), _obj), _applyDecoratedDescriptor(_obj, \"ChangePosition2\", [_dec11], Object.getOwnPropertyDescriptor(_obj, \"ChangePosition2\"), _obj), _applyDecoratedDescriptor(_obj, \"ChangePosition3\", [_dec12], Object.getOwnPropertyDescriptor(_obj, \"ChangePosition3\"), _obj), _applyDecoratedDescriptor(_obj, \"ToggleWireframe\", [_dec13], Object.getOwnPropertyDescriptor(_obj, \"ToggleWireframe\"), _obj), _applyDecoratedDescriptor(_obj, \"loadDrawingPlanes\", [_dec14], Object.getOwnPropertyDescriptor(_obj, \"loadDrawingPlanes\"), _obj), _applyDecoratedDescriptor(_obj, \"loadDXF3D\", [_dec15], Object.getOwnPropertyDescriptor(_obj, \"loadDXF3D\"), _obj), _applyDecoratedDescriptor(_obj, \"SendBase64PNGToServer\", [_dec16], Object.getOwnPropertyDescriptor(_obj, \"SendBase64PNGToServer\"), _obj)), _obj)));\n\n  _exports.default = _default;\n});","define(\"m08-2020/data-adapter\", [\"exports\", \"@ember-data/debug\"], function (_exports, _debug) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _debug.default;\n    }\n  });\n});","define(\"m08-2020/formats\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = {\n    time: {\n      hhmmss: {\n        hour: 'numeric',\n        minute: 'numeric',\n        second: 'numeric'\n      }\n    },\n    date: {\n      hhmmss: {\n        hour: 'numeric',\n        minute: 'numeric',\n        second: 'numeric'\n      }\n    },\n    number: {\n      EUR: {\n        style: 'currency',\n        currency: 'EUR',\n        minimumFractionDigits: 2,\n        maximumFractionDigits: 2\n      },\n      USD: {\n        style: 'currency',\n        currency: 'USD',\n        minimumFractionDigits: 2,\n        maximumFractionDigits: 2\n      }\n    }\n  };\n  _exports.default = _default;\n});","define(\"m08-2020/helpers/app-version\", [\"exports\", \"m08-2020/config/environment\", \"ember-cli-app-version/utils/regexp\"], function (_exports, _environment, _regexp) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.appVersion = appVersion;\n  _exports.default = void 0;\n\n  function appVersion(_, hash = {}) {\n    const version = _environment.default.APP.version; // e.g. 1.0.0-alpha.1+4jds75hf\n    // Allow use of 'hideSha' and 'hideVersion' For backwards compatibility\n\n    let versionOnly = hash.versionOnly || hash.hideSha;\n    let shaOnly = hash.shaOnly || hash.hideVersion;\n    let match = null;\n\n    if (versionOnly) {\n      if (hash.showExtended) {\n        match = version.match(_regexp.versionExtendedRegExp); // 1.0.0-alpha.1\n      } // Fallback to just version\n\n\n      if (!match) {\n        match = version.match(_regexp.versionRegExp); // 1.0.0\n      }\n    }\n\n    if (shaOnly) {\n      match = version.match(_regexp.shaRegExp); // 4jds75hf\n    }\n\n    return match ? match[0] : version;\n  }\n\n  var _default = Ember.Helper.helper(appVersion);\n\n  _exports.default = _default;\n});","define(\"m08-2020/helpers/file-queue\", [\"exports\", \"ember-file-upload/helpers/file-queue\"], function (_exports, _fileQueue) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _fileQueue.default;\n    }\n  });\n});","define(\"m08-2020/helpers/format-date\", [\"exports\", \"ember-intl/helpers/format-date\"], function (_exports, _formatDate) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _formatDate.default;\n    }\n  });\n});","define(\"m08-2020/helpers/format-message\", [\"exports\", \"ember-intl/helpers/format-message\"], function (_exports, _formatMessage) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _formatMessage.default;\n    }\n  });\n});","define(\"m08-2020/helpers/format-number\", [\"exports\", \"ember-intl/helpers/format-number\"], function (_exports, _formatNumber) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _formatNumber.default;\n    }\n  });\n});","define(\"m08-2020/helpers/format-relative\", [\"exports\", \"ember-intl/helpers/format-relative\"], function (_exports, _formatRelative) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _formatRelative.default;\n    }\n  });\n});","define(\"m08-2020/helpers/format-time\", [\"exports\", \"ember-intl/helpers/format-time\"], function (_exports, _formatTime) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _formatTime.default;\n    }\n  });\n});","define(\"m08-2020/helpers/pluralize\", [\"exports\", \"ember-inflector/lib/helpers/pluralize\"], function (_exports, _pluralize) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = _pluralize.default;\n  _exports.default = _default;\n});","define(\"m08-2020/helpers/send\", [\"exports\", \"ember-component-inbound-actions/helpers/send\"], function (_exports, _send) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _send.default;\n    }\n  });\n});","define(\"m08-2020/helpers/singularize\", [\"exports\", \"ember-inflector/lib/helpers/singularize\"], function (_exports, _singularize) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = _singularize.default;\n  _exports.default = _default;\n});","define(\"m08-2020/helpers/t\", [\"exports\", \"ember-intl/helpers/t\"], function (_exports, _t) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _t.default;\n    }\n  });\n});","define(\"m08-2020/initializers/app-version\", [\"exports\", \"ember-cli-app-version/initializer-factory\", \"m08-2020/config/environment\"], function (_exports, _initializerFactory, _environment) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  let name, version;\n\n  if (_environment.default.APP) {\n    name = _environment.default.APP.name;\n    version = _environment.default.APP.version;\n  }\n\n  var _default = {\n    name: 'App Version',\n    initialize: (0, _initializerFactory.default)(name, version)\n  };\n  _exports.default = _default;\n});","define(\"m08-2020/initializers/container-debug-adapter\", [\"exports\", \"ember-resolver/resolvers/classic/container-debug-adapter\"], function (_exports, _containerDebugAdapter) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = {\n    name: 'container-debug-adapter',\n\n    initialize() {\n      let app = arguments[1] || arguments[0];\n      app.register('container-debug-adapter:main', _containerDebugAdapter.default);\n      app.inject('container-debug-adapter:main', 'namespace', 'application:main');\n    }\n\n  };\n  _exports.default = _default;\n});","define(\"m08-2020/initializers/ember-data-data-adapter\", [\"exports\", \"@ember-data/debug/setup\"], function (_exports, _setup) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _setup.default;\n    }\n  });\n});","define(\"m08-2020/initializers/ember-data\", [\"exports\", \"ember-data/setup-container\", \"ember-data\"], function (_exports, _setupContainer, _emberData) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  /*\n    This code initializes EmberData in an Ember application.\n  \n    It ensures that the `store` service is automatically injected\n    as the `store` property on all routes and controllers.\n  */\n  var _default = {\n    name: 'ember-data',\n    initialize: _setupContainer.default\n  };\n  _exports.default = _default;\n});","define(\"m08-2020/initializers/export-application-global\", [\"exports\", \"m08-2020/config/environment\"], function (_exports, _environment) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.initialize = initialize;\n  _exports.default = void 0;\n\n  function initialize() {\n    var application = arguments[1] || arguments[0];\n\n    if (_environment.default.exportApplicationGlobal !== false) {\n      var theGlobal;\n\n      if (typeof window !== 'undefined') {\n        theGlobal = window;\n      } else if (typeof global !== 'undefined') {\n        theGlobal = global;\n      } else if (typeof self !== 'undefined') {\n        theGlobal = self;\n      } else {\n        // no reasonable global, just bail\n        return;\n      }\n\n      var value = _environment.default.exportApplicationGlobal;\n      var globalName;\n\n      if (typeof value === 'string') {\n        globalName = value;\n      } else {\n        globalName = Ember.String.classify(_environment.default.modulePrefix);\n      }\n\n      if (!theGlobal[globalName]) {\n        theGlobal[globalName] = application;\n        application.reopen({\n          willDestroy: function () {\n            this._super.apply(this, arguments);\n\n            delete theGlobal[globalName];\n          }\n        });\n      }\n    }\n  }\n\n  var _default = {\n    name: 'export-application-global',\n    initialize: initialize\n  };\n  _exports.default = _default;\n});","define(\"m08-2020/initializers/model-locale\", [\"exports\", \"ember-model-validator/initializers/model-locale\"], function (_exports, _modelLocale) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _modelLocale.default;\n    }\n  });\n  Object.defineProperty(_exports, \"initialize\", {\n    enumerable: true,\n    get: function () {\n      return _modelLocale.initialize;\n    }\n  });\n});","define(\"m08-2020/instance-initializers/ember-data\", [\"exports\", \"ember-data/initialize-store-service\"], function (_exports, _initializeStoreService) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = {\n    name: 'ember-data',\n    initialize: _initializeStoreService.default\n  };\n  _exports.default = _default;\n});","define(\"m08-2020/lib/CSGMesh\", [\"exports\"], function (_exports) {\n  \"use strict\"; //https://github.com/manthrax/THREE-CSGMesh\n  // ## License\n  //\n  // Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license.\n  // THREE.js rework by thrax\n  // # class CSG\n  // Holds a binary space partition tree representing a 3D solid. Two solids can\n  // be combined using the `union()`, `subtract()`, and `intersect()` methods.\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.CsgFactory = CsgFactory;\n\n  function CsgFactory(THREE) {\n    class CSG {\n      constructor() {\n        this.polygons = [];\n      }\n\n      clone() {\n        var csg = new CSG();\n        csg.polygons = this.polygons.map(function (p) {\n          return p.clone();\n        });\n        return csg;\n      }\n\n      toPolygons() {\n        return this.polygons;\n      }\n\n      union(csg) {\n        var a = new Node(this.clone().polygons);\n        var b = new Node(csg.clone().polygons);\n        a.clipTo(b);\n        b.clipTo(a);\n        b.invert();\n        b.clipTo(a);\n        b.invert();\n        a.build(b.allPolygons());\n        return CSG.fromPolygons(a.allPolygons());\n      }\n\n      subtract(csg) {\n        var a = new Node(this.clone().polygons);\n        var b = new Node(csg.clone().polygons);\n        a.invert();\n        a.clipTo(b);\n        b.clipTo(a);\n        b.invert();\n        b.clipTo(a);\n        b.invert();\n        a.build(b.allPolygons());\n        a.invert();\n        return CSG.fromPolygons(a.allPolygons());\n      }\n\n      intersect(csg) {\n        var a = new Node(this.clone().polygons);\n        var b = new Node(csg.clone().polygons);\n        a.invert();\n        b.clipTo(a);\n        b.invert();\n        a.clipTo(b);\n        b.clipTo(a);\n        a.build(b.allPolygons());\n        a.invert();\n        return CSG.fromPolygons(a.allPolygons());\n      } // Return a new CSG solid with solid and empty space switched. This solid is\n      // not modified.\n\n\n      inverse() {\n        var csg = this.clone();\n        csg.polygons.map(function (p) {\n          p.flip();\n        });\n        return csg;\n      }\n\n    } // Construct a CSG solid from a list of `Polygon` instances.\n\n\n    CSG.fromPolygons = function (polygons) {\n      var csg = new CSG();\n      csg.polygons = polygons;\n      return csg;\n    }; // # class Vector\n    // Represents a 3D vector.\n    //\n    // Example usage:\n    //\n    //     new CSG.Vector(1, 2, 3);\n    //     new CSG.Vector([1, 2, 3]);\n    //     new CSG.Vector({ x: 1, y: 2, z: 3 });\n\n\n    class Vector extends THREE.Vector3 {\n      constructor(x, y, z) {\n        if (arguments.length == 3) super(x, y, z);else if (Array.isArray(x)) super(x[0], x[1], x[2]);else if (typeof x == 'object') super().copy(x);else throw \"Invalid constructor to vector\";\n      }\n\n      clone() {\n        return new Vector(this);\n      }\n\n      negated() {\n        return this.clone().multiplyScalar(-1);\n      }\n\n      plus(a) {\n        return this.clone().add(a);\n      }\n\n      minus(a) {\n        return this.clone().sub(a);\n      }\n\n      times(a) {\n        return this.clone().multiplyScalar(a);\n      }\n\n      dividedBy(a) {\n        return this.clone().divideScalar(a);\n      }\n\n      lerp(a, t) {\n        return this.plus(a.minus(this).times(t));\n      }\n\n      unit() {\n        return this.dividedBy(this.length());\n      }\n\n      cross(a) {\n        return THREE.Vector3.prototype.cross.call(this.clone(), a);\n      }\n\n    } // # class Vertex\n    // Represents a vertex of a polygon. Use your own vertex class instead of this\n    // one to provide additional features like texture coordinates and vertex\n    // colors. Custom vertex classes need to provide a `pos` property and `clone()`,\n    // `flip()`, and `interpolate()` methods that behave analogous to the ones\n    // defined by `CSG.Vertex`. This class provides `normal` so convenience\n    // functions like `CSG.sphere()` can return a smooth vertex normal, but `normal`\n    // is not used anywhere else.\n\n\n    class Vertex {\n      constructor(pos, normal, uv) {\n        this.pos = new Vector(pos);\n        this.normal = new Vector(normal);\n        this.uv = new Vector(uv);\n      }\n\n      clone() {\n        return new Vertex(this.pos.clone(), this.normal.clone(), this.uv.clone());\n      } // Invert all orientation-specific data (e.g. vertex normal). Called when the\n      // orientation of a polygon is flipped.\n\n\n      flip() {\n        this.normal = this.normal.negated();\n      } // Create a new vertex between this vertex and `other` by linearly\n      // interpolating all properties using a parameter of `t`. Subclasses should\n      // override this to interpolate additional properties.\n\n\n      interpolate(other, t) {\n        return new Vertex(this.pos.lerp(other.pos, t), this.normal.lerp(other.normal, t), this.uv.lerp(other.uv, t));\n      }\n\n    }\n\n    ; // # class Plane\n    // Represents a plane in 3D space.\n\n    class Plane {\n      constructor(normal, w) {\n        this.normal = normal;\n        this.w = w;\n      }\n\n      clone() {\n        return new Plane(this.normal.clone(), this.w);\n      }\n\n      flip() {\n        this.normal = this.normal.negated();\n        this.w = -this.w;\n      } // Split `polygon` by this plane if needed, then put the polygon or polygon\n      // fragments in the appropriate lists. Coplanar polygons go into either\n      // `coplanarFront` or `coplanarBack` depending on their orientation with\n      // respect to this plane. Polygons in front or in back of this plane go into\n      // either `front` or `back`.\n\n\n      splitPolygon(polygon, coplanarFront, coplanarBack, front, back) {\n        var COPLANAR = 0;\n        var FRONT = 1;\n        var BACK = 2;\n        var SPANNING = 3; // Classify each point as well as the entire polygon into one of the above\n        // four classes.\n\n        var polygonType = 0;\n        var types = [];\n\n        for (var i = 0; i < polygon.vertices.length; i++) {\n          var t = this.normal.dot(polygon.vertices[i].pos) - this.w;\n          var type = t < -Plane.EPSILON ? BACK : t > Plane.EPSILON ? FRONT : COPLANAR;\n          polygonType |= type;\n          types.push(type);\n        } // Put the polygon in the correct list, splitting it when necessary.\n\n\n        switch (polygonType) {\n          case COPLANAR:\n            (this.normal.dot(polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon);\n            break;\n\n          case FRONT:\n            front.push(polygon);\n            break;\n\n          case BACK:\n            back.push(polygon);\n            break;\n\n          case SPANNING:\n            var f = [],\n                b = [];\n\n            for (var i = 0; i < polygon.vertices.length; i++) {\n              var j = (i + 1) % polygon.vertices.length;\n              var ti = types[i],\n                  tj = types[j];\n              var vi = polygon.vertices[i],\n                  vj = polygon.vertices[j];\n              if (ti != BACK) f.push(vi);\n              if (ti != FRONT) b.push(ti != BACK ? vi.clone() : vi);\n\n              if ((ti | tj) == SPANNING) {\n                var t = (this.w - this.normal.dot(vi.pos)) / this.normal.dot(vj.pos.minus(vi.pos));\n                var v = vi.interpolate(vj, t);\n                f.push(v);\n                b.push(v.clone());\n              }\n            }\n\n            if (f.length >= 3) front.push(new Polygon(f, polygon.shared));\n            if (b.length >= 3) back.push(new Polygon(b, polygon.shared));\n            break;\n        }\n      }\n\n    } // `Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a\n    // point is on the plane.\n\n\n    Plane.EPSILON = 1e-5;\n\n    Plane.fromPoints = function (a, b, c) {\n      var n = b.minus(a).cross(c.minus(a)).unit();\n      return new Plane(n, n.dot(a));\n    }; // # class Polygon\n    // Represents a convex polygon. The vertices used to initialize a polygon must\n    // be coplanar and form a convex loop. They do not have to be `Vertex`\n    // instances but they must behave similarly (duck typing can be used for\n    // customization).\n    //\n    // Each convex polygon has a `shared` property, which is shared between all\n    // polygons that are clones of each other or were split from the same polygon.\n    // This can be used to define per-polygon properties (such as surface color).\n\n\n    class Polygon {\n      constructor(vertices, shared) {\n        this.vertices = vertices;\n        this.shared = shared;\n        this.plane = Plane.fromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);\n      }\n\n      clone() {\n        var vertices = this.vertices.map(function (v) {\n          return v.clone();\n        });\n        return new Polygon(vertices, this.shared);\n      }\n\n      flip() {\n        this.vertices.reverse().map(function (v) {\n          v.flip();\n        });\n        this.plane.flip();\n      }\n\n    } // # class Node\n    // Holds a node in a BSP tree. A BSP tree is built from a collection of polygons\n    // by picking a polygon to split along. That polygon (and all other coplanar\n    // polygons) are added directly to that node and the other polygons are added to\n    // the front and/or back subtrees. This is not a leafy BSP tree since there is\n    // no distinction between internal and leaf nodes.\n\n\n    class Node {\n      constructor(polygons) {\n        this.plane = null;\n        this.front = null;\n        this.back = null;\n        this.polygons = [];\n        if (polygons) this.build(polygons);\n      }\n\n      clone() {\n        var node = new Node();\n        node.plane = this.plane && this.plane.clone();\n        node.front = this.front && this.front.clone();\n        node.back = this.back && this.back.clone();\n        node.polygons = this.polygons.map(function (p) {\n          return p.clone();\n        });\n        return node;\n      } // Convert solid space to empty space and empty space to solid space.\n\n\n      invert() {\n        for (var i = 0; i < this.polygons.length; i++) this.polygons[i].flip();\n\n        this.plane.flip();\n        if (this.front) this.front.invert();\n        if (this.back) this.back.invert();\n        var temp = this.front;\n        this.front = this.back;\n        this.back = temp;\n      } // Recursively remove all polygons in `polygons` that are inside this BSP\n      // tree.\n\n\n      clipPolygons(polygons) {\n        if (!this.plane) return polygons.slice();\n        var front = [],\n            back = [];\n\n        for (var i = 0; i < polygons.length; i++) {\n          this.plane.splitPolygon(polygons[i], front, back, front, back);\n        }\n\n        if (this.front) front = this.front.clipPolygons(front);\n        if (this.back) back = this.back.clipPolygons(back);else back = [];\n        return front.concat(back);\n      } // Remove all polygons in this BSP tree that are inside the other BSP tree\n      // `bsp`.\n\n\n      clipTo(bsp) {\n        this.polygons = bsp.clipPolygons(this.polygons);\n        if (this.front) this.front.clipTo(bsp);\n        if (this.back) this.back.clipTo(bsp);\n      } // Return a list of all polygons in this BSP tree.\n\n\n      allPolygons() {\n        var polygons = this.polygons.slice();\n        if (this.front) polygons = polygons.concat(this.front.allPolygons());\n        if (this.back) polygons = polygons.concat(this.back.allPolygons());\n        return polygons;\n      } // Build a BSP tree out of `polygons`. When called on an existing tree, the\n      // new polygons are filtered down to the bottom of the tree and become new\n      // nodes there. Each set of polygons is partitioned using the first polygon\n      // (no heuristic is used to pick a good split).\n\n\n      build(polygons) {\n        if (!polygons.length) return;\n        if (!this.plane) this.plane = polygons[0].plane.clone();\n        var front = [],\n            back = [];\n\n        for (var i = 0; i < polygons.length; i++) {\n          this.plane.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);\n        }\n\n        if (front.length) {\n          if (!this.front) this.front = new Node();\n          this.front.build(front);\n        }\n\n        if (back.length) {\n          if (!this.back) this.back = new Node();\n          this.back.build(back);\n        }\n      }\n\n    }\n\n    CSG.fromGeometry = function (geom) {\n      if (geom.isBufferGeometry) geom = new THREE.Geometry().fromBufferGeometry(geom);\n      var fs = geom.faces;\n      var vs = geom.vertices;\n      var polys = [];\n      var fm = ['a', 'b', 'c'];\n\n      for (var i = 0; i < fs.length; i++) {\n        var f = fs[i];\n        var vertices = [];\n\n        for (var j = 0; j < 3; j++) vertices.push(new Vertex(vs[f[fm[j]]], f.vertexNormals[j], geom.faceVertexUvs[0][i][j]));\n\n        polys.push(new Polygon(vertices));\n      }\n\n      return CSG.fromPolygons(polys);\n    };\n\n    CSG._tmpm3 = new THREE.Matrix3();\n\n    CSG.fromMesh = function (mesh) {\n      var csg = CSG.fromGeometry(mesh.geometry);\n\n      CSG._tmpm3.getNormalMatrix(mesh.matrix);\n\n      for (var i = 0; i < csg.polygons.length; i++) {\n        var p = csg.polygons[i];\n\n        for (var j = 0; j < p.vertices.length; j++) {\n          var v = p.vertices[j];\n          v.pos.applyMatrix4(mesh.matrix);\n          v.normal.applyMatrix3(CSG._tmpm3);\n        }\n      }\n\n      return csg;\n    };\n\n    CSG.toMesh = function (csg, toMatrix) {\n      var geom = new THREE.Geometry();\n      var ps = csg.polygons;\n      var vs = geom.vertices;\n      var fvuv = geom.faceVertexUvs[0];\n\n      for (var i = 0; i < ps.length; i++) {\n        var p = ps[i];\n        var pvs = p.vertices;\n        var v0 = vs.length;\n        var pvlen = pvs.length;\n\n        for (var j = 0; j < pvlen; j++) vs.push(new THREE.Vector3().copy(pvs[j].pos));\n\n        for (var j = 3; j <= pvlen; j++) {\n          var fc = new THREE.Face3();\n          var fuv = [];\n          fvuv.push(fuv);\n          var fnml = fc.vertexNormals;\n          fc.a = v0;\n          fc.b = v0 + j - 2;\n          fc.c = v0 + j - 1;\n          fnml.push(new THREE.Vector3().copy(pvs[0].normal));\n          fnml.push(new THREE.Vector3().copy(pvs[j - 2].normal));\n          fnml.push(new THREE.Vector3().copy(pvs[j - 1].normal));\n          fuv.push(new THREE.Vector3().copy(pvs[0].uv));\n          fuv.push(new THREE.Vector3().copy(pvs[j - 2].uv));\n          fuv.push(new THREE.Vector3().copy(pvs[j - 1].uv));\n          fc.normal = new THREE.Vector3().copy(p.plane.normal);\n          geom.faces.push(fc);\n        }\n      }\n\n      var inv = new THREE.Matrix4().getInverse(toMatrix);\n      geom.applyMatrix4(inv);\n      geom.verticesNeedUpdate = geom.elementsNeedUpdate = geom.normalsNeedUpdate = true;\n      geom.computeBoundingSphere();\n      geom.computeBoundingBox();\n      var m = new THREE.Mesh(geom);\n      m.matrix.copy(toMatrix);\n      m.matrix.decompose(m.position, m.rotation, m.scale);\n      m.updateMatrixWorld();\n      return m;\n    };\n\n    CSG.ieval = function (tokens, index = 0) {\n      if (typeof tokens === 'string') CSG.currentOp = tokens;else if (tokens instanceof Array) {\n        for (let i = 0; i < tokens.length; i++) CSG.ieval(tokens[i], 0);\n      } else if (typeof tokens === 'object') {\n        var op = CSG.currentOp;\n        tokens.updateMatrix();\n        tokens.updateMatrixWorld();\n        if (!CSG.sourceMesh) CSG.currentPrim = CSG.fromMesh(CSG.sourceMesh = tokens);else {\n          CSG.nextPrim = CSG.fromMesh(tokens);\n          CSG.currentPrim = CSG.currentPrim[op](CSG.nextPrim);\n        }\n        if (CSG.doRemove) tokens.parent.remove(tokens);\n      } //union,subtract,intersect,inverse\n    };\n\n    CSG.eval = function (tokens, doRemove) {\n      //[['add',mesh,mesh,mesh,mesh],['sub',mesh,mesh,mesh,mesh]]\n      CSG.currentOp = null;\n      CSG.sourceMesh = null;\n      CSG.doRemove = doRemove;\n      CSG.ieval(tokens);\n      var result = CSG.toMesh(CSG.currentPrim, CSG.sourceMesh.matrix);\n      result.material = CSG.sourceMesh.material;\n      result.castShadow = result.receiveShadow = true;\n      return result;\n    };\n\n    return CSG;\n  } //export default CsgFactory\n  // Return a new CSG solid representing space in either this solid or in the\n  // solid `csg`. Neither this solid nor the solid `csg` are modified.\n  //\n  //     A.union(B)\n  //\n  //     +-------+            +-------+\n  //     |       |            |       |\n  //     |   A   |            |       |\n  //     |    +--+----+   =   |       +----+\n  //     +----+--+    |       +----+       |\n  //          |   B   |            |       |\n  //          |       |            |       |\n  //          +-------+            +-------+\n  //\n  // Return a new CSG solid representing space in this solid but not in the\n  // solid `csg`. Neither this solid nor the solid `csg` are modified.\n  //\n  //     A.subtract(B)\n  //\n  //     +-------+            +-------+\n  //     |       |            |       |\n  //     |   A   |            |       |\n  //     |    +--+----+   =   |    +--+\n  //     +----+--+    |       +----+\n  //          |   B   |\n  //          |       |\n  //          +-------+\n  //\n  // Return a new CSG solid representing space both this solid and in the\n  // solid `csg`. Neither this solid nor the solid `csg` are modified.\n  //\n  //     A.intersect(B)\n  //\n  //     +-------+\n  //     |       |\n  //     |   A   |\n  //     |    +--+----+   =   +--+\n  //     +----+--+    |       +--+\n  //          |   B   |\n  //          |       |\n  //          +-------+\n  //\n\n});","define(\"m08-2020/lib/ClippingUtils/DynamicSectionalPlane\", [\"exports\", \"three\", \"m08-2020/lib/Utils\"], function (_exports, THREE, _Utils) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.DynamicSectionalPlane = void 0;\n  const utils = new _Utils.Utils(THREE);\n\n  class DynamicSectionalPlane {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.sectionalPlanes = [];\n      this.renderOrder = 1;\n    }\n\n    applySectionalPlanes() {\n      this.sectionalPlanes.forEach(planeData => {\n        let targets = planeData.targets;\n        targets.drawingObjects.forEach(({\n          mesh,\n          clippingPlanes\n        }) => {\n          let targetClippingPlanes = this.sectionalPlanes.filter(plane => clippingPlanes.includes(plane.id));\n          this.clipMesh(planeData, mesh, targetClippingPlanes);\n        });\n        this.addPlaneToGUI(planeData);\n      });\n    }\n\n    initSectionalPlanes(dynamicSectionalPlane) {\n      let planeData = dynamicSectionalPlane.planeData;\n      let sectionalPlaneData = {\n        clippingPlane: this.makePlane(planeData),\n        positionVector: utils.initVector3(planeData.positionVector),\n        id: planeData.id,\n        range: planeData.range,\n        factor: dynamicSectionalPlane.factor,\n        stencilPlanes: [],\n        targets: {\n          drawingObjects: []\n        }\n      };\n      this.sectionalPlanes.push(sectionalPlaneData);\n    }\n\n    addPlaneToGUI(planeData) {\n      const clippingPlane = planeData.clippingPlane;\n      let cutPositionChanger = document.getElementById(\"cut-position-changer\");\n      let baseConstant = clippingPlane.constant;\n      cutPositionChanger.min = -planeData.range;\n      cutPositionChanger.max = planeData.range;\n      cutPositionChanger.value = 0;\n      cutPositionChanger.addEventListener(\"input\", ev => {\n        clippingPlane.constant = baseConstant + parseInt(ev.target.value);\n        this.moveStencilPlanes(planeData);\n      });\n      let cutVisibilityChanger = document.getElementById(\"show-cut\");\n      cutVisibilityChanger.addEventListener(\"change\", ev => this.togglePlaneVisibility(planeData, clippingPlane, ev.target.checked));\n      let cutDirectionChanger = document.getElementById(\"invert-cut\");\n      cutDirectionChanger.addEventListener(\"change\", () => clippingPlane.negate());\n    }\n\n    moveStencilPlanes(planeData) {\n      let {\n        clippingPlane,\n        stencilPlanes\n      } = planeData;\n      stencilPlanes.forEach(({\n        stencilPlane\n      }) => {\n        let projectedPlanePos = stencilPlane.position.clone().projectOnVector(clippingPlane.normal);\n        let clippingPlanePos = clippingPlane.normal.clone().multiplyScalar(-clippingPlane.constant);\n        let delta = clippingPlanePos.sub(projectedPlanePos);\n        stencilPlane.position.add(delta);\n      });\n    }\n\n    clipMesh(planeData, mesh, targetPlanes) {\n      mesh.updateMatrix();\n      let clippingPlane = planeData.clippingPlane;\n      let positionVector = planeData.positionVector;\n      let targetScene = this.GraphicsThree3D.stencilScenes.length ? new THREE.Scene() : this.GraphicsThree3D.scene;\n\n      if (mesh.stencilNeeded) {\n        let stencilAndOutline = {\n          stencilPlane: null,\n          stencilClippingPlanes: targetPlanes,\n          targetMesh: mesh,\n          stencilOpacity: 0.0,\n          targetScene\n        };\n\n        if (mesh.material) {\n          let colorProps = this.getColorPropsFromMaterial(mesh.material, planeData.factor);\n          stencilAndOutline.stencilOpacity = colorProps.alpha / 255.0;\n          let [frontFaceStencilMat, backFaceStencilMat, planeStencilMat] = this.getClippingMaterials(colorProps);\n          this.clipStencilMaterials(clippingPlane, targetPlanes, [frontFaceStencilMat, backFaceStencilMat, planeStencilMat]);\n          let meshGeo = mesh.geometry.clone();\n          let frontMesh = new THREE.Mesh(meshGeo, frontFaceStencilMat);\n          frontMesh.applyMatrix4(mesh.matrix);\n          let backMesh = new THREE.Mesh(meshGeo, backFaceStencilMat);\n          backMesh.applyMatrix4(mesh.matrix);\n          frontMesh.renderOrder = this.renderOrder;\n          backMesh.renderOrder = this.renderOrder;\n          frontMesh.position.copy(mesh.position);\n          backMesh.position.copy(mesh.position);\n          targetScene.add(frontMesh);\n          targetScene.add(backMesh);\n          let planeMesh = this.createStencilPlaneMesh(clippingPlane, positionVector, planeStencilMat);\n          this.GraphicsThree3D.initWireframeObject(planeMesh, new THREE.Mesh(), this.GraphicsThree3D.jsonData, targetScene);\n          targetScene.add(planeMesh);\n          stencilAndOutline.stencilPlane = planeMesh;\n        }\n\n        planeData.stencilPlanes.push(stencilAndOutline);\n      }\n\n      this.GraphicsThree3D.stencilScenes.push(targetScene);\n      if (mesh.children) mesh.children.forEach(child => this.clipMaterial(child.material, clippingPlane));\n      this.clipMaterial(mesh.material, clippingPlane);\n    }\n\n    clipStencilMaterials(clippingPlane, targetPlanes, [frontFaceStencilMat, backFaceStencilMat, planeStencilMat]) {\n      frontFaceStencilMat.clippingPlanes = [clippingPlane];\n      backFaceStencilMat.clippingPlanes = [clippingPlane];\n      planeStencilMat.clippingPlanes = targetPlanes.filter(plane => !plane.clippingPlane.equals(clippingPlane)).map(plane => plane.clippingPlane);\n    }\n\n    createStencilPlaneMesh(clippingPlane, positionVector, planeStencilMat) {\n      let planeNormal = clippingPlane.normal.clone();\n      let forwardVector = new THREE.Vector3(0, 0, -1);\n      let planeGeom = new THREE.PlaneBufferGeometry();\n      let planeMesh = new THREE.Mesh(planeGeom, planeStencilMat);\n      planeMesh.scale.setScalar(1000);\n      planeMesh.position.copy(positionVector);\n      planeMesh.quaternion.setFromUnitVectors(forwardVector, planeNormal);\n\n      planeMesh.onAfterRender = function (renderer) {\n        renderer.clearStencil();\n      };\n\n      planeMesh.renderOrder = this.renderOrder + 0.1;\n      return planeMesh;\n    }\n\n    getClippingMaterials(colorProps) {\n      //https://discourse.threejs.org/t/capping-clipped-planes-using-stencil-on-a-buffergeometry/18407/18\n      // PASS 1\n      // everywhere that the back faces are visible (clipped region) the stencil\n      // buffer is incremented by 1.\n      let backFaceStencilMat = this.createBackStencilMat(); // PASS 2\n      // everywhere that the front faces are visible the stencil\n      // buffer is decremented back to 0.\n\n      let frontFaceStencilMat = this.createFrontStencilMat(); // PASS 3\n      // draw the plane everywhere that the stencil buffer != 0, which will\n      // only be in the clipped region where back faces are visible.\n\n      let planeStencilMat = this.createPlaneStencilMat(colorProps);\n      return [frontFaceStencilMat, backFaceStencilMat, planeStencilMat];\n    }\n\n    createPlaneStencilMat(colorProps) {\n      let planeStencilMat = this.GraphicsThree3D.getMaterialFromColor(colorProps);\n      planeStencilMat.stencilWrite = true;\n      planeStencilMat.stencilRef = 0;\n      planeStencilMat.stencilFunc = THREE.NotEqualStencilFunc;\n      planeStencilMat.stencilFail = THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZFail = THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZPass = THREE.ReplaceStencilOp;\n      return planeStencilMat;\n    }\n\n    createBackStencilMat() {\n      let backFaceStencilMat = new THREE.MeshBasicMaterial();\n      backFaceStencilMat.depthWrite = false;\n      backFaceStencilMat.depthTest = false;\n      backFaceStencilMat.colorWrite = false;\n      backFaceStencilMat.stencilWrite = true;\n      backFaceStencilMat.stencilFunc = THREE.AlwaysStencilFunc;\n      backFaceStencilMat.side = THREE.BackSide;\n      backFaceStencilMat.stencilFail = THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZFail = THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZPass = THREE.IncrementWrapStencilOp;\n      return backFaceStencilMat;\n    }\n\n    createFrontStencilMat() {\n      let frontFaceStencilMat = new THREE.MeshBasicMaterial();\n      frontFaceStencilMat.depthWrite = false;\n      frontFaceStencilMat.depthTest = false;\n      frontFaceStencilMat.colorWrite = false;\n      frontFaceStencilMat.stencilWrite = true;\n      frontFaceStencilMat.stencilFunc = THREE.AlwaysStencilFunc;\n      frontFaceStencilMat.side = THREE.FrontSide;\n      frontFaceStencilMat.stencilFail = THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZFail = THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZPass = THREE.DecrementWrapStencilOp;\n      return frontFaceStencilMat;\n    }\n\n    getColorPropsFromMaterial(meshMaterial, factor) {\n      let material = meshMaterial.length ? meshMaterial[0].clone() : meshMaterial.clone();\n      let {\n        red,\n        green,\n        blue\n      } = this.modifyColorWithFactor(material.color, factor);\n      let colorProps = {\n        alpha: material.opacity * 255,\n        red,\n        green,\n        blue\n      };\n      return colorProps;\n    }\n\n    modifyColorWithFactor(color, factor) {\n      let {\n        r,\n        g,\n        b\n      } = color;\n      let red = r * 255;\n      let green = g * 255;\n      let blue = b * 255;\n\n      if (factor > 0) {\n        red += (255 - red) * factor;\n        green += (255 - green) * factor;\n        blue += (255 - blue) * factor;\n      } else {\n        red += red * factor;\n        green += green * factor;\n        blue += blue * factor;\n      }\n\n      return {\n        red,\n        green,\n        blue\n      };\n    }\n\n    clipMaterial(material, plane) {\n      if (material.length) material.forEach(mat => this.addClippingPlane(mat, plane));else this.addClippingPlane(material, plane);\n    }\n\n    addClippingPlane(material, plane) {\n      if (material.clippingPlanes) material.clippingPlanes.push(plane);else material.clippingPlanes = [plane];\n    }\n\n    togglePlaneVisibility(planeData, clippingPlane, isVisible) {\n      if (isVisible) this.showClippingPlane(planeData, clippingPlane);else this.hideClippingPlane(planeData, clippingPlane);\n    }\n\n    showClippingPlane(planeData, clippingPlane) {\n      planeData.targets.drawingObjects.forEach(meshData => this.addClippingPlaneToMesh(meshData.mesh, clippingPlane));\n      this.addClippingWhenVisible(clippingPlane);\n      planeData.stencilPlanes.forEach(plane => plane.stencilPlane.material.opacity = plane.stencilOpacity);\n    }\n\n    hideClippingPlane(planeData, clippingPlane) {\n      planeData.targets.drawingObjects.forEach(meshData => this.removeClippingPlaneFromMesh(meshData.mesh, clippingPlane));\n      this.removeClippingWhenNotVisible(clippingPlane);\n      planeData.stencilPlanes.forEach(plane => plane.stencilPlane.material.opacity = 0);\n    }\n\n    addClippingWhenVisible(clippingPlane) {\n      this.sectionalPlanes.forEach(planeData => {\n        if (!planeData.clippingPlane.equals(clippingPlane)) {\n          planeData.stencilPlanes.forEach(stencilData => {\n            stencilData.stencilPlane.material.clippingPlanes.push(clippingPlane);\n          });\n        }\n      });\n    }\n\n    removeClippingWhenNotVisible(clippingPlane) {\n      this.sectionalPlanes.forEach(planeData => {\n        planeData.stencilPlanes.forEach(stencilData => {\n          stencilData.stencilPlane.material.clippingPlanes = stencilData.stencilPlane.material.clippingPlanes.filter(cp => !cp.equals(clippingPlane));\n        });\n      });\n    }\n\n    addClippingPlaneToMesh(mesh, plane) {\n      if (mesh.children) mesh.children.forEach(child => {\n        if (child.material.length > 0) child.material.forEach(mat => mat.clippingPlanes.push(plane));else child.material.clippingPlanes.push(plane);\n      });\n      if (mesh.material.length > 0) mesh.material.forEach(mat => mat.clippingPlanes.push(plane));else mesh.material.clippingPlanes.push(plane);\n    }\n\n    removeClippingPlaneFromMesh(mesh, plane) {\n      if (mesh.children) mesh.children.forEach(child => this.removeClippingPlane(child.material, plane));\n      this.removeClippingPlane(mesh.material, plane);\n    }\n\n    removeClippingPlane(material, plane) {\n      if (material.length > 0) material.forEach(mat => mat.clippingPlanes = mat.clippingPlanes.filter(cp => !cp.equals(plane)));else material.clippingPlanes = material.clippingPlanes.filter(cp => !cp.equals(plane));\n    }\n\n    makePlane(planeData) {\n      let positionVector = utils.initVector3(planeData.positionVector);\n      let normalVector = utils.initVector3(planeData.normalVector).negate().normalize();\n      let planeDistance = positionVector.clone().projectOnVector(normalVector).length();\n      let distanceSign = positionVector.normalize().dot(normalVector) > 0 ? -1 : 1;\n      planeDistance *= distanceSign;\n      let plane = new THREE.Plane(normalVector, planeDistance);\n      return plane;\n    }\n\n    clearSectionalPlanes() {\n      this.sectionalPlanes.forEach(planeData => {\n        planeData.stencilPlanes.forEach(stencilPlaneData => stencilPlaneData.targetScene.remove(stencilPlaneData.stencilPLane));\n      });\n      this.sectionalPlanes = [];\n    }\n\n  }\n\n  _exports.DynamicSectionalPlane = DynamicSectionalPlane;\n});","define(\"m08-2020/lib/ClippingUtils/OutlineGenerator\", [\"exports\", \"three\"], function (_exports, THREE) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.OutlineGenerator = void 0;\n  const TOLERANCE = 0.01;\n\n  class OutlineGenerator {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.a = new THREE.Vector3();\n      this.b = new THREE.Vector3();\n      this.c = new THREE.Vector3();\n      this.planePointA = new THREE.Vector3();\n      this.planePointB = new THREE.Vector3();\n      this.planePointC = new THREE.Vector3();\n      this.lineAB = new THREE.Line3(), this.lineBC = new THREE.Line3(), this.lineCA = new THREE.Line3();\n      this.pointOfIntersection = new THREE.Vector3();\n      this.pointsOfIntersection = new THREE.Geometry();\n    }\n\n    drawStencilOutline(obj, mathPlane, lineProps) {\n      let self = this;\n      obj.geometry.faces.forEach(function (face, idx) {\n        obj.localToWorld(self.a.copy(obj.geometry.vertices[face.a]));\n        obj.localToWorld(self.b.copy(obj.geometry.vertices[face.b]));\n        obj.localToWorld(self.c.copy(obj.geometry.vertices[face.c]));\n        self.lineAB = new THREE.Line3(self.a, self.b);\n        self.lineBC = new THREE.Line3(self.b, self.c);\n        self.lineCA = new THREE.Line3(self.c, self.a);\n        self.setPointOfIntersection(self.lineAB, mathPlane, idx);\n        self.setPointOfIntersection(self.lineBC, mathPlane, idx);\n        self.setPointOfIntersection(self.lineCA, mathPlane, idx);\n      });\n      let lines = [];\n      let vertices = this.pointsOfIntersection.vertices;\n      let facesDict = this.getFaceIndexMap(vertices);\n      Object.values(facesDict).forEach(val => {\n        if (val.length > 1) {\n          let line = this.GraphicsThree3D.drawLine(val[0], val[1], lineProps);\n          lines.push(line);\n        }\n      });\n      return lines;\n    }\n\n    getFaceIndexMap(vertices) {\n      let dict = {};\n      vertices.forEach(vertex => {\n        if (dict.hasOwnProperty(vertex.faceIndex)) dict[vertex.faceIndex].push(vertex);else dict[vertex.faceIndex] = [vertex];\n      });\n      return dict;\n    }\n\n    setPointOfIntersection(line, plane, faceIdx) {\n      this.pointOfIntersection = plane.intersectLine(line, new THREE.Vector3());\n\n      if (this.pointOfIntersection && !line.start.equals(this.pointOfIntersection)) {\n        let p = this.pointOfIntersection.clone();\n        p.faceIndex = faceIdx;\n        p.checked = false;\n        this.pointsOfIntersection.vertices.push(p);\n      }\n    }\n\n    getContours(points, contours) {\n      let contour = []; // find first line for the contour\n\n      let firstPointIndex = 0;\n      let secondPointIndex = 0;\n      let firstPoint, secondPoint;\n\n      for (let i = 0; i < points.length; i++) {\n        if (points[i].checked == true) continue;\n        firstPointIndex = i;\n        firstPoint = points[firstPointIndex];\n        firstPoint.checked = true;\n        secondPointIndex = this.getPairIndex(firstPoint, firstPointIndex, points);\n        secondPoint = points[secondPointIndex];\n        secondPoint.checked = true;\n        contour.push(firstPoint.clone());\n        contour.push(secondPoint.clone());\n        break;\n      }\n\n      contour = this.getContour(secondPoint, points, contour);\n      contours.push(contour);\n      let allChecked = 0;\n      points.forEach(p => {\n        allChecked += p.checked == true ? 1 : 0;\n      });\n\n      if (allChecked != points.length) {\n        return this.getContours(points, contours);\n      }\n\n      return contours;\n    }\n\n    getContour(currentPoint, points, contour) {\n      let p1Index = this.getNearestPointIndex(currentPoint, points);\n      let p1 = points[p1Index];\n      p1.checked = true;\n      let p2Index = this.getPairIndex(p1, p1Index, points);\n      let p2 = points[p2Index];\n      p2.checked = true;\n      let isClosed = p2.equals(contour[0], TOLERANCE);\n\n      if (!isClosed) {\n        contour.push(p2.clone());\n        return this.getContour(p2, points, contour);\n      } else {\n        contour.push(contour[0].clone());\n        return contour;\n      }\n    }\n\n    getNearestPointIndex(point, points) {\n      let index = 0;\n\n      for (let i = 0; i < points.length; i++) {\n        let p = points[i];\n\n        if (p.checked == false && p.equals(point, TOLERANCE)) {\n          index = i;\n          break;\n        }\n      }\n\n      return index;\n    }\n\n    getPairIndex(point, pointIndex, points) {\n      let index = 0;\n\n      for (let i = 0; i < points.length; i++) {\n        let p = points[i];\n\n        if (i != pointIndex && p.checked == false && p.faceIndex == point.faceIndex) {\n          index = i;\n          break;\n        }\n      }\n\n      return index;\n    }\n\n    clearPointsOfIntersection() {\n      this.pointOfIntersection = new THREE.Vector3();\n      this.pointsOfIntersection = new THREE.Geometry();\n    }\n\n  }\n\n  _exports.OutlineGenerator = OutlineGenerator;\n});","define(\"m08-2020/lib/ClippingUtils/SectionalPlane\", [\"exports\", \"three\", \"m08-2020/lib/Utils\", \"m08-2020/lib/ClippingUtils/OutlineGenerator\"], function (_exports, THREE, _Utils, _OutlineGenerator) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.SectionalPlane = void 0;\n  let utils = new _Utils.Utils(THREE);\n\n  class SectionalPlane {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.OutlineGenerator = new _OutlineGenerator.OutlineGenerator(GraphicsThree3D);\n      this.clippingPlanes = [];\n      this.clipObjects = [];\n      this.renderOrder = 1;\n      this.sectionalPlanesData = {};\n    }\n\n    addToSectionalPlanes(insertionPoint, object, objectData) {\n      if (this.sectionalPlanesData.hasOwnProperty(objectData.id)) {\n        if (this.sectionalPlanesData[objectData.id].hasOwnProperty(insertionPoint.id)) {\n          this.sectionalPlanesData[objectData.id][insertionPoint.id].push({\n            object,\n            insertionPoint,\n            sectionalPlanes: objectData.components.sectionalPlanes,\n            properties: objectData.properties\n          });\n        } else {\n          this.sectionalPlanesData[objectData.id][insertionPoint.id] = [{\n            object,\n            insertionPoint,\n            sectionalPlanes: objectData.components.sectionalPlanes,\n            properties: objectData.properties\n          }];\n        }\n      } else {\n        this.sectionalPlanesData[objectData.id] = {};\n        this.sectionalPlanesData[objectData.id][insertionPoint.id] = [{\n          object,\n          insertionPoint,\n          sectionalPlanes: objectData.components.sectionalPlanes,\n          properties: objectData.properties\n        }];\n      }\n    }\n\n    applySectionalPlanes() {\n      Object.values(this.sectionalPlanesData).forEach(drawingObj => Object.values(drawingObj).forEach(insertionPt => insertionPt.forEach(data => {\n        let clippingPlanes = this.initClippingPlanes(data.sectionalPlanes, data.insertionPoint);\n        let intersectionLineProps = data.properties.intersectionLine;\n        let intersectionAreaProps = data.properties.intersectionArea;\n        data.object.stencilNeeded = true;\n        clippingPlanes.forEach(clippingPlane => {\n          this.clipMesh(clippingPlane, data.object, intersectionAreaProps, intersectionLineProps, clippingPlanes);\n        });\n      })));\n    }\n\n    initClippingPlanes(sectionalPlanes, insertionPoint) {\n      let clippingPlanes = [];\n      let insertionVector = utils.initVector3(insertionPoint.insertionVector);\n      let rotationAngle = insertionPoint.rotationAngle ? insertionPoint.rotationAngle * Math.PI / 180 : 0;\n      let rotationAxis = rotationAngle ? utils.initVector3(insertionPoint.rotationAxis) : 0;\n      let rotationPoint = rotationAngle ? utils.initVector3(insertionPoint.rotationPoint) : 0;\n      sectionalPlanes.forEach(planeData => {\n        let modifiedPlaneData = {};\n\n        if (rotationAngle && rotationAxis && rotationPoint) {\n          modifiedPlaneData.normalVector = utils.initVector3(planeData.normalVector).applyAxisAngle(rotationAxis, rotationAngle);\n          modifiedPlaneData.positionVector = utils.initVector3(planeData.positionVector).sub(rotationPoint).applyAxisAngle(rotationAxis, rotationAngle).add(rotationPoint).add(insertionVector);\n        } else {\n          modifiedPlaneData.normalVector = planeData.normalVector;\n          modifiedPlaneData.positionVector = {\n            x: planeData.positionVector.x + insertionPoint.insertionVector.x,\n            y: planeData.positionVector.y + insertionPoint.insertionVector.y,\n            z: planeData.positionVector.z + insertionPoint.insertionVector.z\n          };\n        }\n\n        clippingPlanes.push({\n          clippingPlane: this.makePlane(modifiedPlaneData),\n          positionVector: utils.initVector3(modifiedPlaneData.positionVector)\n        });\n      });\n      return clippingPlanes;\n    }\n\n    applySectionalPlane(planeData, intersectionAreaProps, intersectionLineProps) {\n      this.clipObjects.forEach(({\n        object,\n        insertionPoint\n      }) => {\n        if (object.type == \"Mesh\" || object.type == \"Line\" || object.type == \"LineSegments\") {\n          this.clipMesh(planeData, object, insertionPoint, intersectionAreaProps, intersectionLineProps);\n        }\n      });\n    }\n\n    makePlane(planeData) {\n      let positionVector = utils.initVector3(planeData.positionVector);\n      let normalVector = utils.initVector3(planeData.normalVector).negate().normalize();\n      let planeDistance = positionVector.clone().projectOnVector(normalVector).length();\n      let distanceSign = positionVector.normalize().dot(normalVector) > 0 ? -1 : 1;\n      planeDistance *= distanceSign;\n      let plane = new THREE.Plane(normalVector, planeDistance);\n      return plane;\n    }\n\n    clipMesh(planeData, mesh, intersectionAreaProps, lineProps, clippingPlanes) {\n      mesh.updateMatrix();\n      mesh.updateMatrixWorld();\n      let clippingPlane = planeData.clippingPlane;\n      let positionVector = planeData.positionVector;\n      let targetScene = this.GraphicsThree3D.stencilScenes.length ? new THREE.Scene() : this.GraphicsThree3D.scene;\n\n      if (mesh.stencilNeeded) {\n        if (this.areaPropsDefined(intersectionAreaProps)) {\n          let [frontFaceStencilMat, backFaceStencilMat, planeStencilMat] = this.getClippingMaterials(intersectionAreaProps);\n          frontFaceStencilMat.clippingPlanes = [clippingPlane];\n          backFaceStencilMat.clippingPlanes = [clippingPlane];\n          planeStencilMat.clippingPlanes = clippingPlanes.filter(plane => !plane.clippingPlane.equals(clippingPlane)).map(plane => plane.clippingPlane);\n          let meshGeo = mesh.geometry.clone();\n          let frontMesh = new THREE.Mesh(meshGeo, frontFaceStencilMat);\n          frontMesh.applyMatrix4(mesh.matrix);\n          let backMesh = new THREE.Mesh(meshGeo, backFaceStencilMat);\n          backMesh.applyMatrix4(mesh.matrix);\n          frontMesh.renderOrder = this.renderOrder;\n          backMesh.renderOrder = this.renderOrder;\n          targetScene.add(frontMesh);\n          targetScene.add(backMesh);\n          let planeNormal = clippingPlane.normal.clone();\n          let forwardVector = new THREE.Vector3(0, 0, -1);\n          let planeGeom = new THREE.PlaneBufferGeometry();\n          let planeMesh = new THREE.Mesh(planeGeom, planeStencilMat);\n          planeMesh.scale.setScalar(1000);\n          planeMesh.position.copy(positionVector);\n          planeMesh.quaternion.setFromUnitVectors(forwardVector, planeNormal);\n          frontMesh.position.copy(mesh.position);\n          backMesh.position.copy(mesh.position);\n\n          planeMesh.onAfterRender = function (renderer) {\n            renderer.clearStencil();\n          };\n\n          planeMesh.renderOrder = this.renderOrder + 0.1;\n          this.GraphicsThree3D.initWireframeObject(planeMesh, new THREE.Mesh(), this.GraphicsThree3D.jsonData, targetScene);\n          targetScene.add(planeMesh);\n        }\n      }\n\n      if (lineProps) {\n        let lines = this.OutlineGenerator.drawStencilOutline(mesh, clippingPlane, lineProps);\n        this.OutlineGenerator.clearPointsOfIntersection();\n        lines.forEach(line => {\n          line.material.clippingPlanes = clippingPlanes.map(p => p.clippingPlane);\n          targetScene.add(line);\n        });\n      }\n\n      this.GraphicsThree3D.stencilScenes.push(targetScene);\n      if (mesh.children) mesh.children.forEach(child => this.clipMaterial(child.material, clippingPlane));\n      this.clipMaterial(mesh.material, clippingPlane);\n    }\n\n    clipMaterial(material, plane) {\n      if (material.length) material.forEach(mat => this.addClippingPlane(mat, plane));else this.addClippingPlane(material, plane);\n    }\n\n    addClippingPlane(material, plane) {\n      if (material.clippingPlanes) material.clippingPlanes.push(plane);else material.clippingPlanes = [plane];\n    }\n\n    getClippingMaterials(materialProps) {\n      let frontFaceStencilMat, backFaceStencilMat, planeStencilMat; //https://discourse.threejs.org/t/capping-clipped-planes-using-stencil-on-a-buffergeometry/18407/18\n      // PASS 1\n      // everywhere that the back faces are visible (clipped region) the stencil\n      // buffer is incremented by 1.\n\n      backFaceStencilMat = new THREE.MeshBasicMaterial();\n      backFaceStencilMat.depthWrite = false;\n      backFaceStencilMat.depthTest = false;\n      backFaceStencilMat.colorWrite = false;\n      backFaceStencilMat.stencilWrite = true;\n      backFaceStencilMat.stencilFunc = THREE.AlwaysStencilFunc;\n      backFaceStencilMat.side = THREE.BackSide;\n      backFaceStencilMat.stencilFail = THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZFail = THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZPass = THREE.IncrementWrapStencilOp; // PASS 2\n      // everywhere that the front faces are visible the stencil\n      // buffer is decremented back to 0.\n\n      frontFaceStencilMat = new THREE.MeshBasicMaterial();\n      frontFaceStencilMat.depthWrite = false;\n      frontFaceStencilMat.depthTest = false;\n      frontFaceStencilMat.colorWrite = false;\n      frontFaceStencilMat.stencilWrite = true;\n      frontFaceStencilMat.stencilFunc = THREE.AlwaysStencilFunc;\n      frontFaceStencilMat.side = THREE.FrontSide;\n      frontFaceStencilMat.stencilFail = THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZFail = THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZPass = THREE.DecrementWrapStencilOp; // PASS 3\n      // draw the plane everywhere that the stencil buffer != 0, which will\n      // only be in the clipped region where back faces are visible.\n\n      planeStencilMat = this.getPlaneStencilMaterial(materialProps);\n      planeStencilMat.stencilWrite = true;\n      planeStencilMat.stencilRef = 0;\n      planeStencilMat.stencilFunc = THREE.NotEqualStencilFunc;\n      planeStencilMat.stencilFail = THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZFail = THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZPass = THREE.ReplaceStencilOp;\n      return [frontFaceStencilMat, backFaceStencilMat, planeStencilMat];\n    }\n\n    getPlaneStencilMaterial(areaProps) {\n      const SIZE = 20;\n      let planeStencilMat;\n      let colorProps = areaProps.color;\n\n      if (areaProps.hatching.type === 2) {\n        let orientationVector = utils.normalizeVector(areaProps.hatching.orientationVector);\n        let hatchSpacing = areaProps.hatching.factor;\n        let hatchColor = areaProps.hatching.color;\n        let hatchThickness = areaProps.hatching.thickness;\n        planeStencilMat = this.GraphicsThree3D.makeCanvasMaterial(colorProps, hatchColor, orientationVector, hatchSpacing, hatchThickness);\n        planeStencilMat.map.wrapS = planeStencilMat.map.wrapT = THREE.RepeatWrapping;\n        planeStencilMat.map.repeat.set(SIZE, SIZE);\n      } else if (areaProps.hatching.type === 1) {\n        planeStencilMat = this.GraphicsThree3D.getMaterialFromColor(colorProps);\n      }\n\n      return planeStencilMat;\n    }\n\n    areaPropsDefined(areaProps) {\n      return areaProps && areaProps.hatching.type > 0 && areaProps.hatching.type < 3;\n    }\n\n    resetClipObjects() {\n      this.clipObjects = [];\n    }\n\n  }\n\n  _exports.SectionalPlane = SectionalPlane;\n});","define(\"m08-2020/lib/DXFGenerator\", [\"exports\", \"three\", \"m08-2020/lib/Utils\", \"m08-2020/lib/dxf_colors\"], function (_exports, THREE, _Utils, _dxf_colors) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.DXFGenerator = void 0;\n  let utils = new _Utils.Utils(THREE);\n\n  class DXFGenerator {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D; // global dxf data -->\n\n      this.blockSection = \"\";\n      this.entitiesSection = \"\";\n      this.textStyles = \"\";\n      this.offsetFromTop = 0; // object data -->\n\n      this.referenceZeroPoint = new THREE.Vector3();\n      this.scaleFactor = 1;\n      this.blocks = {\n        fasteners: [],\n        drawingObjects: []\n      };\n      this.projectedPoints = [];\n      this.wireframePoints = [];\n      this.fastenerPoints = {};\n      this.pointObjectsData = [];\n      this.lineObjectsData = []; // TODO: Might need better solution.\n\n      this.outerFrameOffset = 0;\n      this.drawingScaleBarBBox = null;\n      this.drawingSizeHalf = {\n        width: 0,\n        height: 0\n      };\n    }\n\n    downloadDXF3D() {\n      this.generateBlockAndEntitySections3D();\n      let contentDXF = this.generateContentDXF();\n      this.downloadTextFile(\"scene.dxf\", contentDXF.trim());\n    }\n\n    generateBlockAndEntitySections3D() {\n      this.positionCamera();\n      this.drawingSizeHalf = {\n        width: this.GraphicsThree3D.camera.right,\n        height: this.GraphicsThree3D.camera.top\n      }; // TODO: Might need to refactor?\n\n      try {\n        this.getScale(this.wireframePoints, {\n          x: 1,\n          y: -1,\n          z: -1\n        });\n      } catch (error) {\n        console.error(error);\n        console.error(\"DXFGenerator: Cannot generate scale. Setting scale to 1.\");\n        this.scaleFactor = 1;\n      }\n\n      try {\n        this.referenceZeroPoint = this.getProjectedReferenceZeroPoint();\n      } catch (error) {\n        console.error(error);\n        console.error(\"DXFGenerator: Cannot set projected reference zero point. Setting projected reference zero point to (0, 0, 0).\");\n        this.referenceZeroPoint = new THREE.Vector3();\n      } //\n\n\n      let visProps = {\n        dxfFastenerVisualisation: {\n          addOn: true,\n          axis: true,\n          fastener: false\n        },\n        visualisation: {\n          arrow: true,\n          dimensionalChain: true,\n          drawingObject: true,\n          fastener: true\n        }\n      };\n      this.addToBlockSection(visProps);\n      this.addToEntitiesSection(visProps);\n    }\n\n    positionCamera() {\n      let controls = this.GraphicsThree3D.controls;\n      let camera = this.GraphicsThree3D.camera;\n      let midVector = this.GraphicsThree3D.objectMidVector;\n      let initialPos = this.GraphicsThree3D.initialPosition;\n      let cameraTargetPos = {\n        x: midVector.x + initialPos.x,\n        y: midVector.y + initialPos.y,\n        z: midVector.z + initialPos.z\n      };\n      camera.position.set(cameraTargetPos.x, cameraTargetPos.y, cameraTargetPos.z);\n      camera.zoom = 1;\n      camera.lookAt(midVector);\n      camera.updateProjectionMatrix();\n      controls.update();\n    }\n\n    downloadDXF2D(dxfName, drawingPlaneData) {\n      this.generateBlockAndEntitySections(drawingPlaneData);\n      let contentDXF = this.generateContentDXF();\n      this.downloadTextFile(dxfName, contentDXF.trim());\n      this.clearDXF();\n    }\n\n    generateContentDXF() {\n      let contentDXF = \"\"; ///\n      // Set units to centimeters\n\n      contentDXF += \"0\\nSECTION\\n2\\nHEADER\\n9\\n$INSUNITS\\n70\\n5\\n0\\nENDSEC\\n\"; ///\n\n      contentDXF += `0\\nSECTION\\n2\\nTABLES\\n0\\nTABLE\\n2\\nSTYLE\\n${this.textStyles}0\\nENDTAB\\n0\\nENDSEC\\n`;\n      contentDXF += `0\\nSECTION\\n2\\nBLOCKS\\n${this.blockSection}0\\nENDSEC\\n`;\n      contentDXF += `0\\nSECTION\\n2\\nENTITIES\\n${this.entitiesSection}0\\nENDSEC\\n0\\nEOF`;\n      return contentDXF;\n    }\n\n    generateBlockAndEntitySections(drawingPlaneData) {\n      this.GraphicsThree3D.camera.updateProjectionMatrix();\n      this.outerFrameOffset = drawingPlaneData.drawingComponents.frameDataAndProps.frameProps.outerLine.thickness / 2;\n      this.setDrawingSizeHalf(drawingPlaneData.drawingComponents.frameDataAndProps.frameData, drawingPlaneData.drawingComponents.frameDataAndProps.frameProps); // TODO: Might need to refactor?\n\n      try {\n        this.getScale(this.wireframePoints, drawingPlaneData.normal);\n      } catch (error) {\n        console.error(error);\n        console.error(\"DXFGenerator: Cannot generate scale. Setting scale to 1.\");\n        this.scaleFactor = 1;\n      }\n\n      try {\n        this.referenceZeroPoint = this.getProjectedReferenceZeroPoint();\n      } catch (error) {\n        console.error(error);\n        console.error(\"DXFGenerator: Cannot set projected reference zero point. Setting projected reference zero point to (0, 0, 0).\");\n        this.referenceZeroPoint = new THREE.Vector3();\n      } //\n\n\n      this.addToBlockSection(drawingPlaneData);\n      this.addToEntitiesSection(drawingPlaneData);\n      this.createDrawingTextStyles(drawingPlaneData);\n      this.addDrawingFrame(drawingPlaneData.drawingComponents.frameDataAndProps);\n      this.addDrawingFreeTexts(drawingPlaneData.drawingComponents.freeTextDataAndProps);\n      this.addDrawingScaleTextBlock(drawingPlaneData.drawingComponents.scaleTextBlockDataAndProps, drawingPlaneData.scale);\n      this.addDrawingUnitTextBlock(drawingPlaneData.drawingComponents.unitTextBlockDataAndProps, drawingPlaneData.units);\n      this.addDrawingScaleBar(drawingPlaneData.drawingComponents.scaleBarDataAndProps, drawingPlaneData.scale, drawingPlaneData.units);\n      this.offsetFromTop += drawingPlaneData.drawingComponents.frameDataAndProps.frameData.height;\n      this.clearObjectData();\n    }\n\n    addToBlockSection(drawingPlaneData) {\n      let visualisation = drawingPlaneData.visualisation;\n      if (visualisation.fastener) this.blockSection += this.generateFastenerBlocks(drawingPlaneData, this.fastenerPoints);\n    }\n\n    addToEntitiesSection(drawingPlaneData) {\n      let visualisation = drawingPlaneData.visualisation;\n\n      if (visualisation.drawingObject) {\n        this.drawWireframeLines(this.wireframePoints).forEach(line => this.entitiesSection += `${line.trim()}\\n`);\n        this.drawPoints(this.pointObjectsData).forEach(point => this.entitiesSection += `${point.trim()}\\n`);\n        this.drawLines(this.lineObjectsData).forEach(line => this.entitiesSection += `${line.trim()}\\n`);\n      }\n\n      if (visualisation.fastener) {\n        this.blocks.fasteners.forEach(({\n          blockName,\n          layerName\n        }) => this.entitiesSection += `0\\nINSERT\\n2\\n${blockName}\\n8\\n${layerName}\\n10\\n${this.referenceZeroPoint.x}\\n20\\n${this.referenceZeroPoint.y}\\n30\\n${this.referenceZeroPoint.z}\\n`);\n      }\n    }\n\n    createDrawingTextStyles(drawingPlaneData) {\n      this.createDrawingTextStyle(drawingPlaneData.drawingComponents.freeTextDataAndProps.freeTextProps);\n      this.createDrawingTextStyle(drawingPlaneData.drawingComponents.scaleTextBlockDataAndProps.scaleTextBlockProps);\n      this.createDrawingTextStyle(drawingPlaneData.drawingComponents.unitTextBlockDataAndProps.unitTextBlockProps);\n      this.createDrawingTextStyle(drawingPlaneData.drawingComponents.scaleBarDataAndProps.scaleBarProps.text);\n    }\n\n    createDrawingTextStyle(textProps) {\n      let fontName = this.generateFontName(textProps); //\"ARIAL.TTF\";\n\n      this.textStyles += `0\\nSTYLE\\n2\\n${fontName}\\n70\\n0\\n40\\n0\\n41\\n0\\n50\\n0\\n71\\n0\\n42\\n0\\n3\\n${fontName + \".TTF\"}\\n`;\n    }\n\n    generateFontName(textProps) {\n      let name = \"\";\n\n      if (textProps) {\n        let {\n          style,\n          type\n        } = textProps;\n\n        switch (type) {\n          case 1:\n            name += \"ARIAL_\";\n            break;\n\n          case 2:\n            name += \"CALIBRI_\";\n            break;\n\n          case 3:\n            name += \"COURIER_\";\n            break;\n\n          case 4:\n            name += \"TIMESNEWROMAN_\";\n            break;\n\n          default:\n            break;\n        }\n\n        switch (style) {\n          case 1:\n            name += \"REGULAR\";\n            break;\n\n          case 2:\n            name += \"ITALIC\";\n            break;\n\n          case 3:\n            name += \"BOLD\";\n            break;\n\n          case 4:\n            name += \"BOLD_ITALIC\";\n            break;\n\n          default:\n            break;\n        }\n      } else name += \"ARIAL\";\n\n      return name;\n    }\n\n    addDrawingScaleBar(scaleBarDataAndProps, scale, units) {\n      let {\n        scaleBarData,\n        scaleBarProps\n      } = scaleBarDataAndProps;\n\n      if (scaleBarData && scaleBarProps) {\n        let areaProps = scaleBarProps.area;\n        let lineProps = scaleBarProps.line;\n        let textProps = scaleBarProps.text;\n        let areaColor = this.getColorIndexFromColor(this.getColorFromProps(areaProps));\n        let lineColor = this.getColorIndexFromColor(this.getColorFromProps(lineProps));\n        const NUM_OF_SEGMENTS = 5;\n        const SEGMENT_SIZE = 1;\n        const TEXT_ALIGNMENT = 1;\n        const Z_AXIS = new THREE.Vector3(0, 0, 1);\n        let insertionPoint = utils.initVector3(scaleBarData.insertionPoint);\n        let bboxSize = this.drawingScaleBarBBox.getSize(new THREE.Vector3());\n        let centerOffset = this.drawingScaleBarBBox.getCenter(new THREE.Vector3());\n        let alignmentOffset = this.GraphicsThree3D.DrawingPlaneLoader.getScaleBarAlignmentOffset(bboxSize, scaleBarData.relativePosition);\n        let rotation = this.getRotationFromDirection(scaleBarData.directionVector) * Math.PI / 180;\n        let barHeight = scaleBarData.height;\n        let barWidth = SEGMENT_SIZE * NUM_OF_SEGMENTS; /// Line -->\n\n        let linePoints = [new THREE.Vector3(0, 0, 0), new THREE.Vector3(barWidth, 0, 0), new THREE.Vector3(barWidth, barHeight, 0), new THREE.Vector3(0, barHeight, 0), new THREE.Vector3(0, 0, 0)].map(pt => pt.sub(centerOffset).add(alignmentOffset).applyAxisAngle(Z_AXIS, rotation).add(insertionPoint).sub(new THREE.Vector3(0, this.offsetFromTop, 0)));\n\n        for (let i = 0; i < linePoints.length - 1; i++) this.entitiesSection += this.drawLine(linePoints[i], linePoints[i + 1], lineColor, 0); /// <--\n        /// Fills -->\n\n\n        let solidPoints = [];\n\n        for (let i = 0; i < NUM_OF_SEGMENTS; i++) {\n          if (i % 2) solidPoints.push([new THREE.Vector3(SEGMENT_SIZE * i, 0, 0), new THREE.Vector3(SEGMENT_SIZE * (i + 1), 0, 0), new THREE.Vector3(SEGMENT_SIZE * i, barHeight, 0), new THREE.Vector3(SEGMENT_SIZE * (i + 1), barHeight, 0)].map(pt => pt.sub(centerOffset).add(alignmentOffset).applyAxisAngle(Z_AXIS, rotation).add(insertionPoint).sub(new THREE.Vector3(0, this.offsetFromTop, 0))));\n        }\n\n        solidPoints.forEach(ptArr => this.entitiesSection += this.drawSolid(ptArr[0], ptArr[1], ptArr[2], ptArr[3], areaColor, 0)); /// <--\n        /// Texts -->\n\n        let decimalPlaces = scaleBarData.decimalPlaces;\n        let distance = scaleBarData.distance;\n        let height = scaleBarData.height;\n        let textOffset = scaleBarData.textOffset;\n        let scaleFactor = this.GraphicsThree3D.DrawingPlaneLoader.getScaleFactor(units.length);\n        let heightOffset = -distance - textProps.size / 2;\n        let content = \"\";\n        let position = new THREE.Vector3(0, heightOffset, 0);\n\n        for (let i = 0; i <= NUM_OF_SEGMENTS; i++) {\n          content = (i * scale * scaleFactor).toFixed(decimalPlaces);\n          if (i === 5 && units.length) content += ` ${units.length}`;\n\n          if (textOffset) {\n            if (i % 2 === 1) position.y = height - heightOffset;else position.y = heightOffset;\n          }\n\n          position.x = i * SEGMENT_SIZE;\n          let textPosition = position.clone().sub(centerOffset).add(alignmentOffset).add(insertionPoint);\n          let textData = {\n            content,\n            directionVector: scaleBarData.directionVector,\n            insertionPoint: textPosition,\n            relativePosition: TEXT_ALIGNMENT\n          };\n          this.entitiesSection += this.makeTextFromDataAndProps(textData, textProps);\n        } /// <--\n\n      }\n    }\n\n    addDrawingUnitTextBlock(unitTextBlockDataAndProps, units) {\n      let {\n        unitTextBlockData,\n        unitTextBlockProps\n      } = unitTextBlockDataAndProps;\n\n      if (unitTextBlockData && unitTextBlockProps) {\n        let textData = { ...unitTextBlockData\n        };\n        textData.content = this.GraphicsThree3D.DrawingPlaneLoader.generateUnitTextContent(unitTextBlockData, units);\n        this.entitiesSection += this.makeTextFromDataAndProps(textData, unitTextBlockProps);\n      }\n    }\n\n    addDrawingScaleTextBlock(scaleTextBlockDataAndProps, scale) {\n      let {\n        scaleTextBlockData,\n        scaleTextBlockProps\n      } = scaleTextBlockDataAndProps;\n\n      if (scaleTextBlockData && scaleTextBlockProps) {\n        let textData = { ...scaleTextBlockData\n        };\n        textData.content = `${scaleTextBlockData.text} ${scale.toFixed(scaleTextBlockData.decimals)}`;\n        this.entitiesSection += this.makeTextFromDataAndProps(textData, scaleTextBlockProps);\n      }\n    }\n\n    addDrawingFreeTexts(freeTextDataAndProps) {\n      let {\n        freeTexts,\n        freeTextProps\n      } = freeTextDataAndProps;\n\n      if (freeTexts && freeTextProps) {\n        freeTexts.forEach(text => this.entitiesSection += this.makeTextFromDataAndProps(text, freeTextProps));\n      }\n    }\n\n    makeTextFromDataAndProps(textData, textProps) {\n      let {\n        size,\n        heightWidthRatio\n      } = textProps;\n      let color = this.getColorIndexFromColor(this.getColorFromProps(textProps));\n      let fontName = this.generateFontName(textProps);\n      let {\n        content,\n        directionVector,\n        relativePosition\n      } = textData;\n      let justifications = this.getTextJustifications(relativePosition);\n      let rotation = this.getRotationFromDirection(directionVector);\n      let insertionPoint = { ...textData.insertionPoint\n      };\n      insertionPoint.y -= this.offsetFromTop;\n      insertionPoint.z = 0;\n      let textParams = {\n        content,\n        position: insertionPoint,\n        height: size,\n        widthRatio: heightWidthRatio,\n        justifications,\n        rotation,\n        color,\n        fontName,\n        layerName: 0\n      };\n      return this.drawText(textParams);\n    }\n\n    getRotationFromDirection(directionVector) {\n      let xAxis = new THREE.Vector2(1, 0, 0);\n      let direction = utils.initVector2(directionVector).normalize();\n      let dot = direction.dot(xAxis);\n      let cross = direction.cross(xAxis);\n      let rotation = Math.acos(dot) * (cross < 0 ? 1 : -1) * 180 / Math.PI;\n      return rotation;\n    }\n\n    getTextJustifications(relativePosition) {\n      let justifications = {\n        justificHorizontal: 0,\n        justificVertical: 0\n      };\n\n      switch (relativePosition) {\n        case 1:\n          justifications.justificHorizontal = 1;\n          justifications.justificVertical = 2;\n          break;\n\n        case 2:\n          justifications.justificHorizontal = 0;\n          justifications.justificVertical = 1;\n          break;\n\n        case 3:\n          justifications.justificHorizontal = 0;\n          justifications.justificVertical = 3;\n          break;\n\n        case 4:\n          justifications.justificHorizontal = 2;\n          justifications.justificVertical = 3;\n          break;\n\n        case 5:\n          justifications.justificHorizontal = 2;\n          justifications.justificVertical = 1;\n          break;\n\n        default:\n          break;\n      }\n\n      return justifications;\n    }\n\n    drawSolid(p1, p2, p3, p4, color, layerName) {\n      let solid = `0\\nSOLID\\n8\\n${layerName}\\n62\\n${color}\\n` + `10\\n${p1.x}\\n20\\n${p1.y}\\n30\\n${p1.y}\\n11\\n${p2.x}\\n21\\n${p2.y}\\n31\\n${p2.z}\\n` + `12\\n${p3.x}\\n22\\n${p3.y}\\n32\\n${p3.z}\\n13\\n${p4.x}\\n23\\n${p4.y}\\n33\\n${p4.z}\\n`;\n      return solid;\n    }\n\n    drawText({\n      content,\n      position,\n      height,\n      widthRatio,\n      justifications,\n      rotation,\n      color,\n      fontName,\n      layerName\n    }) {\n      let {\n        justificHorizontal,\n        justificVertical\n      } = justifications;\n      let text = `0\\nTEXT\\n8\\n${layerName}\\n1\\n${content}\\n40\\n${height}\\n41\\n${widthRatio}\\n72\\n${justificHorizontal}\\n73\\n${justificVertical}\\n` + `50\\n${rotation}\\n62\\n${color}\\n7\\n${fontName}\\n10\\n${0}\\n20\\n${0}\\n30\\n${0}\\n` + `11\\n${position.x}\\n21\\n${position.y}\\n31\\n${position.z}\\n`;\n      return text;\n    }\n\n    addDrawingFrame(frameDataAndProps) {\n      let {\n        frameData,\n        frameProps\n      } = frameDataAndProps;\n      this.generateFrameOuterLine(frameData, frameProps.outerLine);\n      this.generateFrameInnerLine(frameData, frameProps.innerLine);\n    }\n\n    generateFrameOuterLine(frameData, outerProps) {\n      let {\n        width,\n        height\n      } = frameData;\n      let thickness = 0; //outerProps.thickness;\n\n      let color = this.getColorIndexFromColor(this.getColorFromProps(outerProps));\n      let outerPoints = [{\n        x: 0,\n        y: -this.offsetFromTop,\n        z: 0\n      }, {\n        x: width,\n        y: -this.offsetFromTop,\n        z: 0\n      }, {\n        x: width,\n        y: height - this.offsetFromTop,\n        z: 0\n      }, {\n        x: 0,\n        y: height - this.offsetFromTop,\n        z: 0\n      }, {\n        x: 0,\n        y: -this.offsetFromTop,\n        z: 0\n      }];\n\n      for (let i = 0; i < outerPoints.length - 1; i++) {\n        let extrudeDirection = i % 2 ? {\n          x: 0,\n          y: 1,\n          z: 0\n        } : {\n          x: 1,\n          y: 0,\n          z: 0\n        };\n        this.entitiesSection += this.drawThickLine(outerPoints[i], outerPoints[i + 1], color, thickness, extrudeDirection, 0);\n      }\n    }\n\n    generateFrameInnerLine(frameData, innerProps) {\n      let {\n        width,\n        height\n      } = frameData;\n      let {\n        left,\n        right,\n        top,\n        bottom\n      } = frameData.border;\n      let thickness = 0; //innerProps.thickness;\n\n      let color = this.getColorIndexFromColor(this.getColorFromProps(innerProps));\n      let innerPoints = [{\n        x: left,\n        y: -this.offsetFromTop + bottom,\n        z: 0\n      }, {\n        x: width - right,\n        y: -this.offsetFromTop + bottom,\n        z: 0\n      }, {\n        x: width - right,\n        y: -this.offsetFromTop + height - top,\n        z: 0\n      }, {\n        x: left,\n        y: -this.offsetFromTop + height - top,\n        z: 0\n      }, {\n        x: left,\n        y: -this.offsetFromTop + bottom,\n        z: 0\n      }];\n\n      for (let i = 0; i < innerPoints.length - 1; i++) {\n        let extrudeDirection = i % 2 ? {\n          x: 0,\n          y: 1,\n          z: 0\n        } : {\n          x: 1,\n          y: 0,\n          z: 0\n        };\n        this.entitiesSection += this.drawThickLine(innerPoints[i], innerPoints[i + 1], color, thickness, extrudeDirection, 0);\n      }\n    }\n\n    getProjectedReferenceZeroPoint() {\n      let camera = this.GraphicsThree3D.camera;\n      return this.projectPointOnScreen(new THREE.Vector3(), camera, this.drawingSizeHalf.width, this.drawingSizeHalf.height);\n    }\n\n    getScale(wireframePoints, planeNormal) {\n      let pointPairs = wireframePoints[0].pointPairs;\n      let planeDistance = 0,\n          index = 0;\n\n      while (planeDistance < 0.1) {\n        let pointPair = pointPairs[index];\n        let normalVec = utils.initVector3(planeNormal);\n        let projectedOnPlane = pointPair.map(point => point.clone().projectOnPlane(normalVec));\n        planeDistance = projectedOnPlane[0].distanceTo(projectedOnPlane[1]);\n        index++;\n      }\n\n      let {\n        x,\n        y\n      } = this.GraphicsThree3D.renderer.getSize(new THREE.Vector2());\n      this.scaleFactor = x / y / (this.drawingSizeHalf.width / this.drawingSizeHalf.height);\n    }\n\n    generateFastenerBlocks(drawingPlaneData, fastenerPoints) {\n      const CAMERA = this.GraphicsThree3D.camera;\n      let fastenerBlocks = \"\";\n      let dxfFastenerVisualisation = drawingPlaneData.dxfFastenerVisualisation;\n      const POINT_RADIUS = 0.1;\n      Object.entries(fastenerPoints).forEach(([id, pointData]) => {\n        let blockName = `${drawingPlaneData.id}_${id}`;\n        let layerName = `fastener_${id}`;\n        this.blocks.fasteners.push({\n          blockName,\n          layerName\n        });\n        fastenerBlocks += `0\\nBLOCK\\n8\\n${layerName}\\n2\\n${blockName}\\n70\\n0\\n10\\n${this.referenceZeroPoint.x}\\n20\\n${this.referenceZeroPoint.y}\\n30\\n${this.referenceZeroPoint.x}\\n3\\n${blockName}\\n`;\n\n        if (dxfFastenerVisualisation.axis) {\n          pointData.axis.forEach(({\n            pointPair,\n            properties\n          }) => {\n            let projectedPoints = this.getProjectedPointsArr([pointPair], CAMERA);\n            let lineColor = this.getColorIndexFromColor(this.getColorFromProps(properties.line));\n            let pointColor = this.getColorIndexFromColor(this.getColorFromProps(properties.point));\n            projectedPoints.forEach(ptsPair => fastenerBlocks += this.drawLine(ptsPair[0], ptsPair[1], lineColor, layerName));\n            projectedPoints.forEach(ptsPair => fastenerBlocks += this.drawCircle(ptsPair[0], POINT_RADIUS, pointColor, layerName));\n          });\n        }\n\n        if (dxfFastenerVisualisation.addOn) {\n          pointData.addon.forEach(({\n            points,\n            properties\n          }) => {\n            let color = this.getColorIndexFromColor(this.getColorFromProps(properties));\n            let projectedPoints = this.getProjectedPointsArr(points, CAMERA);\n            projectedPoints.forEach(pointsArr => {\n              for (let i = 0; i < pointsArr.length - 1; i++) fastenerBlocks += this.drawLine(pointsArr[i], pointsArr[i + 1], color, layerName);\n            });\n          });\n        }\n\n        fastenerBlocks += \"0\\nENDBLK\\n\";\n      });\n      return fastenerBlocks;\n    }\n\n    drawLines(linesData) {\n      let lines = [];\n      linesData.forEach(line => {\n        let color = this.getColorIndexFromColor(this.getColorFromProps(line.properties));\n        let projectedPointPairs = this.getProjectedPointsArr(line.pointPairs, this.GraphicsThree3D.camera);\n        projectedPointPairs.forEach(pair => lines.push(this.drawLine(pair[0], pair[1], color, `drawingObject_${line.id}`)));\n      });\n      return lines;\n    }\n\n    drawPoints(pointsData) {\n      let points = [];\n      pointsData.forEach(point => {\n        let color = this.getColorIndexFromColor(this.getColorFromProps(point.properties));\n        let radius = point.properties.size / 2;\n        let centerPos = utils.initVector3(point.position);\n        let projectedCenterPos = this.projectPointOnScreen(centerPos, this.GraphicsThree3D.camera, this.drawingSizeHalf.width, this.drawingSizeHalf.height);\n        points.push(this.drawCircle(projectedCenterPos, radius, color, `drawingObject_${point.id}`));\n      });\n      return points;\n    }\n\n    drawCircle(center, radius, color, layerName) {\n      return `0\\nCIRCLE\\n8\\n${layerName}\\n62\\n${color}\\n40\\n${radius}\\n10\\n${center.x}\\n20\\n${center.y}\\n30\\n${center.z}\\n`;\n    }\n\n    drawArc(center, radius, color, layerName) {\n      const START_ANGLE = 0,\n            END_ANGLE = 359.9;\n      return `0\\nARC\\n8\\n${layerName}\\n62\\n${color}\\n10\\n${center.x}\\n20\\n${center.y}\\n30\\n${center.z}\\n40\\n${radius}\\n50\\n${START_ANGLE}\\n51\\n${END_ANGLE}`;\n    }\n\n    getProjectedPointsArr(ptPairs, camera) {\n      return ptPairs.map(pair => this.getProjectedPoints(pair, camera));\n    }\n\n    getProjectedPoints(points, camera) {\n      return points.map(pt => this.projectPointOnScreen(pt, camera));\n    }\n\n    projectPointOnScreen(point, camera) {\n      let widthHalf = this.drawingSizeHalf.width;\n      let heightHalf = this.drawingSizeHalf.height;\n      let projectedPoint = point.clone();\n      projectedPoint.project(camera);\n      projectedPoint.x = projectedPoint.x * widthHalf + widthHalf - this.outerFrameOffset;\n      projectedPoint.y = projectedPoint.y * heightHalf + heightHalf - this.offsetFromTop;\n      projectedPoint.z = 0;\n      this.projectedPoints.push(projectedPoint);\n      return projectedPoint;\n    }\n\n    setDrawingSizeHalf(frameData, frameProps) {\n      this.drawingSizeHalf = {\n        width: (frameData.width + frameProps.outerLine.thickness) / 2,\n        height: (frameData.height + frameProps.outerLine.thickness) / 2\n      };\n    }\n\n    getFacesFromScene(scene) {\n      let faces = [];\n      scene.traverse(child => {\n        if (child.addToDXF) {\n          faces.push(...this.getMeshFaces(child));\n        }\n      });\n      return faces;\n    }\n\n    getMeshFaces(mesh) {\n      let faces = [];\n      let color = this.getColorIndexFromColor(mesh.material[0].color);\n      let geometry = mesh.geometry;\n      let meshFaces = geometry.faces;\n      let meshVertices = geometry.vertices;\n      meshFaces.forEach(face => {\n        let vectorA = meshVertices[face.a].clone();\n        let vectorB = meshVertices[face.b].clone();\n        let vectorC = meshVertices[face.c].clone();\n        vectorA.applyMatrix4(mesh.matrix);\n        vectorB.applyMatrix4(mesh.matrix);\n        vectorC.applyMatrix4(mesh.matrix);\n        faces.push(this.drawFace(vectorA, vectorB, vectorC, color, mesh.dxfLayer));\n      });\n      return faces;\n    }\n\n    drawWireframeLines(wireframePoints) {\n      let lines = [];\n      wireframePoints.forEach(({\n        lineProps,\n        pointPairs,\n        id\n      }) => {\n        let color = this.getColorIndexFromColor(this.getColorFromProps(lineProps));\n        let projectedPoints = this.getProjectedPointsArr(pointPairs, this.GraphicsThree3D.camera);\n        let layerName = `drawingObject_${id}`;\n        projectedPoints.forEach(ptsPair => lines.push(this.drawLine(ptsPair[0], ptsPair[1], color, layerName)));\n      });\n      return lines;\n    }\n\n    drawThickLine(p1, p2, color, thickness, extrudeDirection, layerName) {\n      let line = `0\\nLINE\\n8\\n${layerName}\\n62\\n${color}\\n10\\n${p1.x}\\n20\\n${p1.y}\\n30\\n${p1.z}\\n11\\n${p2.x}\\n21\\n${p2.y}\\n31\\n${p2.z}\\n` + `39\\n${thickness}\\n210\\n${extrudeDirection.x}\\n220\\n${extrudeDirection.y}\\n230\\n${extrudeDirection.z}\\n`;\n      return line;\n    }\n\n    drawLine(p1, p2, color, layerName) {\n      return `0\\nLINE\\n8\\n${layerName}\\n62\\n${color}\\n10\\n${p1.x}\\n20\\n${p1.y}\\n30\\n${p1.z}\\n11\\n${p2.x}\\n21\\n${p2.y}\\n31\\n${p2.z}\\n`;\n    }\n\n    drawFace(p1, p2, p3, color, layerName) {\n      let face = [`0\\n3DFACE\\n8\\n${layerName}\\n62\\n${color}`, `10\\n${p1.x}\\n20\\n${p1.y}\\n30\\n${p1.z}`, `11\\n${p2.x}\\n21\\n${p2.y}\\n31\\n${p2.z}`, `12\\n${p3.x}\\n22\\n${p3.y}\\n32\\n${p3.z}`, `13\\n${p3.x}\\n23\\n${p3.y}\\n33\\n${p3.z}`].join(\"\\n\");\n      return face;\n    }\n\n    getColorIndexFromColor(color) {\n      let colorRGB = this.getRGBFromColor(color);\n      let colorIndex = this.getColorIndexFromRGB(colorRGB);\n      return colorIndex;\n    }\n\n    getColorIndexFromRGB([r, g, b]) {\n      let minDistance = Infinity;\n      let matchedIndex = 0;\n\n      for (let i = 0; i < 255; i++) {\n        let lookupColor = _dxf_colors.COLOR_LOOKUP[i];\n        let distance = Math.pow(r - lookupColor[0], 2) + Math.pow(g - lookupColor[1], 2) + Math.pow(b - lookupColor[2], 2);\n\n        if (distance < minDistance) {\n          minDistance = distance;\n          matchedIndex = i;\n        }\n      }\n\n      return matchedIndex;\n    }\n\n    getRGBFromColor(color) {\n      return [255 * color.r, 255 * color.g, 255 * color.b];\n    }\n\n    getColorFromProps(props) {\n      return {\n        r: props.color.red / 255,\n        g: props.color.green / 255,\n        b: props.color.blue / 255\n      };\n    }\n\n    downloadTextFile(filename, text) {\n      let element = document.createElement('a');\n      element.setAttribute('href', `data:text/plain;charset=utf-8,${text}`);\n      element.setAttribute('download', filename);\n      element.style.display = 'none';\n      document.body.appendChild(element);\n      element.click();\n      document.body.removeChild(element);\n    }\n\n    clearObjectData() {\n      this.referenceZeroPoint = new THREE.Vector3();\n      this.scaleFactor = 1;\n      this.blocks = {\n        fasteners: [],\n        drawingObjects: []\n      };\n      this.projectedPoints = [];\n      this.wireframePoints = [];\n      this.fastenerPoints = {};\n      this.pointObjectsData = [];\n      this.lineObjectsData = [];\n      this.outerFrameOffset = 0;\n      this.drawingScaleBarBBox = null;\n      this.drawingSizeHalf = {\n        width: 0,\n        height: 0\n      };\n    }\n\n    clearDXF() {\n      this.blockSection = \"\";\n      this.entitiesSection = \"\";\n      this.textStyles = \"\";\n      this.offsetFromTop = 0;\n      this.clearObjectData();\n    }\n\n  }\n\n  _exports.DXFGenerator = DXFGenerator;\n});","define(\"m08-2020/lib/FigureLoaders/ArrowLoader\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.ArrowLoader = void 0;\n\n  class ArrowLoader {\n    constructor(THREE, fontUrlArray, GraphicsThree3D) {\n      this.THREE = THREE;\n      this.fontUrlArray = fontUrlArray;\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.utils = GraphicsThree3D.utils;\n      this.lineRenderOrder = -103; ///\n\n      this.drawArrows = this.drawArrows.bind(this);\n    }\n\n    drawArrows(arrowData) {\n      let meshArray = [];\n      let materialProps = {\n        lineProps: arrowData.properties.line,\n        volumeProps: arrowData.properties.volume,\n        textProps: arrowData.properties.text,\n        areaProps: arrowData.properties.area\n      };\n      let insertionPoints = arrowData.insertionPoints;\n      let forceArrows = arrowData.components.forceArrows;\n      let momentArrows = arrowData.components.momentArrows;\n      let grainDirectionArrows = arrowData.components.grainDirectionArrows;\n\n      if (forceArrows) {\n        forceArrows.forEach(forceArrow => meshArray.push(this.drawForceArrow(forceArrow, materialProps, insertionPoints, arrowData)));\n      }\n\n      if (momentArrows) {\n        momentArrows.forEach(momentArrow => meshArray.push(this.drawMomentArrows(momentArrow, materialProps, insertionPoints, arrowData)));\n      }\n\n      if (grainDirectionArrows) {\n        grainDirectionArrows.forEach(grainDirectionArrow => meshArray.push(this.drawGrainDirectionArrow(grainDirectionArrow, materialProps, insertionPoints, arrowData)));\n      }\n\n      meshArray.forEach(arrow => this.GraphicsThree3D.addObjectToVisControl(arrow, \"arrow\"));\n      return meshArray;\n    }\n\n    addToDimChainCollisionDetection(obj) {\n      obj.updateMatrix();\n      obj.traverse(child => {\n        if (child.type === \"Mesh\") {\n          let intersectionObject = child.clone();\n          intersectionObject.applyMatrix4(obj.matrix);\n          let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(intersectionObject);\n          this.GraphicsThree3D.DimensionalChainIntersectionDetection.meshArr.push(intersectionObjects);\n        }\n      });\n    }\n\n    drawGrainDirectionArrow(grainDirectionArrowData, materialProps, insertionPoints, arrowData) {\n      let insertionPoint = grainDirectionArrowData.insertionPoint;\n      let grainDirectionArrows = new this.THREE.Group();\n\n      if (grainDirectionArrowData.directionVector && grainDirectionArrowData.normalVector && (grainDirectionArrowData.directionVector.x || grainDirectionArrowData.directionVector.y || grainDirectionArrowData.directionVector.z) && (grainDirectionArrowData.normalVector.x || grainDirectionArrowData.normalVector.y || grainDirectionArrowData.normalVector.z)) {\n        let directionVector = this.utils.initVector3(grainDirectionArrowData.directionVector);\n        let normalVector = this.utils.initVector3(grainDirectionArrowData.normalVector);\n\n        if (!directionVector.dot(normalVector) && grainDirectionArrowData.height > 0 && grainDirectionArrowData.length.value1 > 0 && grainDirectionArrowData.length.value2 > 0) {\n          let mainLength = grainDirectionArrowData.length.value1;\n          let miniLength = grainDirectionArrowData.length.value2;\n          let miniHeight = grainDirectionArrowData.height / 2;\n          let mainPointLeft = new this.THREE.Vector3(-mainLength / 2, 0, 0);\n          let mainPointRight = new this.THREE.Vector3(mainLength / 2, 0, 0);\n          let miniPointLeft = mainPointLeft.clone().add(new this.THREE.Vector3(miniLength, miniHeight, 0));\n          let miniPointRight = mainPointRight.clone().add(new this.THREE.Vector3(-miniLength, -miniHeight, 0));\n          insertionPoints.forEach(point => {\n            let grainDirectionArrow = new this.THREE.Object3D();\n\n            if (insertionPoint) {\n              let arrowMesh = this.utils.drawConnectedLines([miniPointLeft, mainPointLeft, mainPointRight, miniPointRight], materialProps.lineProps);\n              let newUpVector = new this.THREE.Vector3().crossVectors(normalVector, directionVector);\n              let dotProduct = arrowMesh.up.dot(newUpVector);\n              let rotationAngle = -Math.acos(dotProduct); // by default THREE.js rotates counterclockwise, so I switched sign (correct?)\n\n              arrowMesh.rotateOnAxis(normalVector, rotationAngle);\n              arrowMesh.up = newUpVector;\n              arrowMesh.lookAt(arrowMesh.position.clone().add(normalVector));\n              grainDirectionArrow.add(arrowMesh);\n              grainDirectionArrow.position.set(insertionPoint.x, insertionPoint.y, insertionPoint.z);\n            }\n\n            if (materialProps.textProps) {\n              this.addTextToArrow(materialProps.textProps, arrowData.components.texts, grainDirectionArrow, insertionPoint);\n            }\n\n            let insertionVector = point.insertionVector;\n            let angle = point.rotationAngle * Math.PI / 180;\n            let rotationAxis, rotationPoint;\n\n            if (angle) {\n              rotationAxis = this.utils.initVector3(point.rotationAxis);\n              rotationPoint = this.utils.initVector3(point.rotationPoint);\n            }\n\n            let pivotPoint = new this.THREE.Object3D();\n\n            if (angle) {\n              pivotPoint.position.copy(rotationPoint);\n              pivotPoint.attach(grainDirectionArrow);\n              pivotPoint.rotateOnAxis(rotationAxis, angle);\n            } else {\n              pivotPoint.attach(grainDirectionArrow);\n            }\n\n            pivotPoint.position.x += insertionVector.x;\n            pivotPoint.position.y += insertionVector.y;\n            pivotPoint.position.z += insertionVector.z;\n            this.addToDimChainCollisionDetection(grainDirectionArrow);\n            grainDirectionArrows.add(pivotPoint);\n          });\n        }\n      }\n\n      return grainDirectionArrows;\n    }\n\n    drawMomentArrows(momentArrowData, materialProps, insertionPoints, arrowData) {\n      let insertionPoint = momentArrowData.insertionPoint;\n      let headRadius = momentArrowData.headSize.value2 / 2;\n      let headHeight = momentArrowData.headSize.value1;\n      let size = momentArrowData.size;\n      let arcAngle = momentArrowData.arcAngle;\n      let volumeMaterial = this.getMaterialFromColor(materialProps.volumeProps.color);\n      let lineMaterial = this.getMaterialFromColor(materialProps.lineProps.color); // TODO: Move this for loop outside this function\n\n      let momentArrows = new this.THREE.Group();\n      insertionPoints.forEach(point => {\n        let insertionVector = point.insertionVector;\n        let rotationAngle = point.rotationAngle * Math.PI / 180;\n        let rotationAxis, rotationPoint;\n\n        if (rotationAngle) {\n          rotationAxis = this.utils.initVector3(point.rotationAxis);\n          rotationPoint = this.utils.initVector3(point.rotationPoint);\n        }\n\n        let momentArrow = new this.THREE.Object3D();\n\n        if (insertionPoint) {\n          if (!arcAngle && momentArrowData.directionVector1 && (momentArrowData.directionVector1.x || momentArrowData.directionVector1.y || momentArrowData.directionVector1.z)) {\n            let directionVectorOne = this.utils.initVector3(momentArrowData.directionVector1);\n            let pointer = this.makeArrow(headRadius, headHeight, volumeMaterial, lineMaterial, materialProps.lineProps);\n            pointer.rotation.z = Math.PI;\n            let pointerTwo = pointer.clone();\n            pointer.position.y += headHeight;\n            let arrow = new this.THREE.Object3D();\n            let axisPointOne = new this.THREE.Vector3(0, 0, 0);\n            let axisPointTwo = new this.THREE.Vector3(0, size, 0);\n            let axisMesh = this.GraphicsThree3D.drawLine(axisPointOne, axisPointTwo, materialProps.lineProps);\n            arrow.add(axisMesh);\n            arrow.add(pointer);\n            arrow.add(pointerTwo);\n            arrow.rotation.x = -Math.PI / 2;\n            let pivot = new this.THREE.Object3D();\n            pivot.add(arrow);\n            pivot.lookAt(directionVectorOne);\n            momentArrow.add(pivot);\n          } else if (arcAngle && momentArrowData.directionVector1 && momentArrowData.directionVector2 && (momentArrowData.directionVector1.x || momentArrowData.directionVector1.y || momentArrowData.directionVector1.z) && (momentArrowData.directionVector2.x || momentArrowData.directionVector2.y || momentArrowData.directionVector2.z)) {\n            let directionVectorOne = this.utils.initVector3(momentArrowData.directionVector1);\n            let directionVectorTwo = this.utils.initVector3(momentArrowData.directionVector2);\n\n            if (!directionVectorOne.dot(directionVectorTwo)) {\n              let pointer = this.makeArrow(headRadius, headHeight, volumeMaterial, lineMaterial, materialProps.lineProps, true);\n              pointer.rotation.z = Math.PI;\n              console.log(arcAngle);\n              let correctedArcAngle = arcAngle;\n              if (correctedArcAngle > 360 || correctedArcAngle < -360) materialProps.lineProps.thickness = 0;\n              if (correctedArcAngle > 360) correctedArcAngle = 360;\n              if (correctedArcAngle < -360) correctedArcAngle = -360;\n              let curveObject = new this.THREE.Object3D();\n              let curveAngle = correctedArcAngle * Math.PI / 180;\n              let startAngle, endAngle;\n\n              if (curveAngle > 0) {\n                startAngle = 0;\n                endAngle = curveAngle;\n              } else {\n                startAngle = curveAngle;\n                endAngle = 0;\n              }\n\n              let curve = new this.THREE.EllipseCurve(0, 0, size / 2, size / 2, startAngle, endAngle, false, 0);\n              let curvePoints = curve.getPoints(50).map(point => new this.THREE.Vector3(point.x, point.y, 0));\n              let curveMesh = this.utils.drawConnectedLines(curvePoints, materialProps.lineProps);\n              let pointDir = new this.THREE.Vector3();\n\n              if (curveAngle > 0) {\n                for (let i = curvePoints.length - 2; i >= 0; i--) {\n                  let distance = Math.round(curvePoints[curvePoints.length - 1].distanceTo(curvePoints[i]));\n\n                  if (distance == Math.round(headHeight)) {\n                    pointDir.subVectors(curvePoints[curvePoints.length - 1], curvePoints[i]).normalize();\n                    break;\n                  }\n                }\n\n                pointer.rotation.x = -Math.PI / 2;\n                let object = new this.THREE.Object3D();\n                object.add(pointer);\n                object.lookAt(pointDir);\n                object.position.x += curvePoints[curvePoints.length - 1].x;\n                object.position.y += curvePoints[curvePoints.length - 1].y;\n                pointer = object;\n              } else {\n                for (let i = 0; i < curvePoints.length; i++) {\n                  let distance = Math.round(curvePoints[0].distanceTo(curvePoints[i]));\n\n                  if (distance == Math.round(headHeight)) {\n                    pointDir.subVectors(curvePoints[0], curvePoints[i]).normalize();\n                    break;\n                  }\n                }\n\n                pointer.rotation.x = -Math.PI / 2;\n                let object = new this.THREE.Object3D();\n                object.add(pointer);\n                object.lookAt(pointDir);\n                object.position.x += curvePoints[0].x;\n                object.position.y += curvePoints[0].y;\n                pointer = object;\n              }\n\n              curveObject.add(curveMesh);\n              curveObject.add(pointer);\n              this.GraphicsThree3D.alignObjectWithVectors(curveObject, new this.THREE.Vector3(0, 0, 0), directionVectorOne, directionVectorTwo);\n              momentArrow.add(curveObject);\n            }\n          }\n\n          momentArrow.position.set(insertionPoint.x, insertionPoint.y, insertionPoint.z);\n        }\n\n        if (materialProps.textProps) {\n          this.addTextToArrow(materialProps.textProps, arrowData.components.texts, momentArrow, insertionPoint);\n        }\n\n        let pivotPoint = new this.THREE.Object3D();\n\n        if (rotationAngle) {\n          pivotPoint.position.copy(rotationPoint);\n          pivotPoint.attach(momentArrow);\n          pivotPoint.rotateOnAxis(rotationAxis, rotationAngle);\n        } else {\n          pivotPoint.attach(momentArrow);\n        }\n\n        pivotPoint.position.x += insertionVector.x;\n        pivotPoint.position.y += insertionVector.y;\n        pivotPoint.position.z += insertionVector.z;\n        this.addToDimChainCollisionDetection(momentArrow);\n        momentArrows.add(pivotPoint);\n      });\n      return momentArrows;\n    }\n\n    drawForceArrow(forceArrowData, materialProps, insertionPoints, arrowData) {\n      let forceArrows = new this.THREE.Group();\n      let headSize = forceArrowData.headSize;\n      let height = forceArrowData.height;\n      let length = forceArrowData.length;\n      let insertionProps = {\n        insertionPoint: forceArrowData.insertionPoint,\n        directionVectorOne: forceArrowData.directionVector1,\n        directionVectorTwo: forceArrowData.directionVector2,\n        directionVectorThree: forceArrowData.directionVector3\n      };\n      let division = forceArrowData.division;\n      let tiltAngle = forceArrowData.tiltAngle;\n      insertionPoints.forEach(point => {\n        let insertionVector = this.utils.initVector3(point.insertionVector);\n        let rotationAngle = point.rotationAngle * Math.PI / 180;\n        let rotationAxis, rotationPoint;\n\n        if (rotationAngle) {\n          rotationAxis = this.utils.initVector3(point.rotationAxis);\n          rotationPoint = this.utils.initVector3(point.rotationPoint);\n        }\n\n        let newArrow;\n        if (!length.value1 && !length.value2) newArrow = this.drawPointForceArrow(forceArrowData, headSize, height, materialProps, insertionProps, arrowData);else if (length.value1 > 0 || length.value2 > 0) newArrow = this.drawLineForceArrow(forceArrowData, materialProps, insertionProps, division, tiltAngle, arrowData);\n        let pivotPoint = new this.THREE.Object3D();\n\n        if (rotationAngle) {\n          pivotPoint.position.copy(rotationPoint);\n          pivotPoint.attach(newArrow);\n          pivotPoint.rotateOnAxis(rotationAxis, rotationAngle);\n        } else {\n          pivotPoint.attach(newArrow);\n        }\n\n        pivotPoint.position.add(insertionVector);\n        forceArrows.add(pivotPoint);\n      });\n      return forceArrows;\n    }\n\n    drawLineForceArrow(forceArrowData, materialProps, insertionProps, division, tiltAngle, arrowData) {\n      // TODO: Will need directionVectors\n      let pointerRadius = forceArrowData.headSize.value2 / 2;\n      let pointerHeight = forceArrowData.headSize.value1;\n      let offsetAngle = tiltAngle * Math.PI / 180;\n      let horizontalLength = forceArrowData.length.value1;\n      let depthLength = forceArrowData.length.value2;\n      let heightLeft = forceArrowData.height.value1;\n      let heightRight = forceArrowData.height.value2;\n      let lineProps = materialProps.lineProps;\n      let volumeMaterial = this.getMaterialFromColor(materialProps.volumeProps.color);\n      let borderMaterial = this.getMaterialFromColor(lineProps.color);\n      let areaMaterial;\n      if (materialProps.areaProps && materialProps.areaProps.color.alpha) areaMaterial = this.getMaterialFromColor(materialProps.areaProps.color);\n      let lineForceArrow = new this.THREE.Object3D();\n      let directionsDefined = forceArrowData.directionVector1 && forceArrowData.directionVector2 && forceArrowData.directionVector3 && (forceArrowData.directionVector1.x || forceArrowData.directionVector1.y || forceArrowData.directionVector1.z) && (forceArrowData.directionVector2.x || forceArrowData.directionVector2.y || forceArrowData.directionVector2.z) && (!(heightLeft && heightRight) || forceArrowData.directionVector3.x || forceArrowData.directionVector3.y || forceArrowData.directionVector3.z);\n      let areOrthogonal = false;\n      let dirVectorNormal, dirVectorHorizontal;\n\n      if (directionsDefined) {\n        if (depthLength) {\n          dirVectorHorizontal = this.utils.initVector3(forceArrowData.directionVector2).normalize();\n          dirVectorNormal = this.utils.initVector3(forceArrowData.directionVector3).normalize();\n          let vectorOne = this.utils.initVector3(forceArrowData.directionVector1).normalize();\n          if (!dirVectorHorizontal.dot(dirVectorNormal) && !vectorOne.dot(dirVectorHorizontal) && !vectorOne.dot(dirVectorNormal)) areOrthogonal = true;\n        } else {\n          dirVectorHorizontal = this.utils.initVector3(forceArrowData.directionVector2).normalize();\n          dirVectorNormal = new this.THREE.Vector3().crossVectors(dirVectorHorizontal, this.utils.initVector3(forceArrowData.directionVector1).negate().normalize());\n          if (!dirVectorHorizontal.dot(dirVectorNormal)) areOrthogonal = true;\n        }\n\n        if (areOrthogonal && insertionProps.insertionPoint && !(depthLength && !horizontalLength) && tiltAngle > -90 && tiltAngle < 90) {\n          let botAxisPointOne = new this.THREE.Vector3(0, 0, 0);\n          let botAxisPointTwo = new this.THREE.Vector3(horizontalLength * Math.cos(offsetAngle), horizontalLength * Math.sin(offsetAngle), 0);\n          let topAxisPointOne = new this.THREE.Vector3(0, heightLeft, 0);\n          let topAxisPointTwo = new this.THREE.Vector3(horizontalLength * Math.cos(offsetAngle), horizontalLength * Math.sin(offsetAngle) + heightRight, 0);\n          let botLine = this.GraphicsThree3D.drawLine(botAxisPointOne, botAxisPointTwo, lineProps);\n          let topLine = this.GraphicsThree3D.drawLine(topAxisPointOne, topAxisPointTwo, lineProps);\n          botLine.renderOrder = this.lineRenderOrder;\n          topLine.renderOrder = this.lineRenderOrder;\n          lineForceArrow.add(botLine);\n          lineForceArrow.add(topLine);\n\n          if (depthLength > 0) {\n            let depthBotAxisPointOne = botAxisPointOne.clone().add(new this.THREE.Vector3(0, 0, depthLength));\n            let depthBotAxisPointTwo = botAxisPointTwo.clone().add(new this.THREE.Vector3(0, 0, depthLength));\n            let depthTopAxisPointOne = topAxisPointOne.clone().add(new this.THREE.Vector3(0, 0, depthLength));\n            let depthTopAxisPointTwo = topAxisPointTwo.clone().add(new this.THREE.Vector3(0, 0, depthLength));\n            let depthBotLine = this.GraphicsThree3D.drawLine(depthBotAxisPointOne, depthBotAxisPointTwo, lineProps);\n            let depthTopLine = this.GraphicsThree3D.drawLine(depthTopAxisPointOne, depthTopAxisPointTwo, lineProps);\n            depthBotLine.renderOrder = this.lineRenderOrder;\n            depthTopLine.renderOrder = this.lineRenderOrder;\n            lineForceArrow.add(depthBotLine);\n            lineForceArrow.add(depthTopLine);\n            let pointContainer = [[botAxisPointOne, depthBotAxisPointOne], [botAxisPointTwo, depthBotAxisPointTwo], [topAxisPointOne, depthTopAxisPointOne], [topAxisPointTwo, depthTopAxisPointTwo]];\n\n            if (areaMaterial) {\n              let bottomPlaneGeo = this.getPlaneGeoFromPoints([botAxisPointOne, botAxisPointTwo, depthBotAxisPointTwo, depthBotAxisPointOne]);\n              let bottomPlane = new this.THREE.Mesh(bottomPlaneGeo, areaMaterial);\n              lineForceArrow.add(bottomPlane);\n              bottomPlane.renderOrder = 102;\n\n              bottomPlane.onBeforeRender = function (renderer) {\n                renderer.clearDepth();\n              };\n\n              if (heightLeft && heightRight) {\n                let topPlaneGeo = this.getPlaneGeoFromPoints([topAxisPointOne, topAxisPointTwo, depthTopAxisPointTwo, depthTopAxisPointOne]);\n                let topPlane = new this.THREE.Mesh(topPlaneGeo, areaMaterial);\n                lineForceArrow.add(topPlane);\n                topPlane.renderOrder = 102;\n\n                topPlane.onBeforeRender = function (renderer) {\n                  renderer.clearDepth();\n                };\n              }\n            }\n\n            pointContainer.forEach(points => {\n              let lineMesh = this.GraphicsThree3D.drawLine(points[0], points[1], lineProps);\n              lineForceArrow.add(lineMesh);\n            });\n          }\n\n          let horizontalDivisions = division.value1;\n          let horizontalSegmentLength = horizontalLength / horizontalDivisions;\n          let depthDivisions = division.value2;\n          let depthSegmentLength = depthLength / depthDivisions;\n          let pointer = this.makeArrow(pointerRadius, pointerHeight, volumeMaterial, borderMaterial, lineProps);\n          pointer.rotation.z = Math.PI;\n\n          for (let i = 1; i < depthDivisions; i++) {\n            let bottomPointOne = new this.THREE.Vector3(0, 0, i * depthSegmentLength);\n            let topPointOne = bottomPointOne.clone().add(new this.THREE.Vector3(0, heightLeft, 0));\n            let bottomPointTwo = bottomPointOne.clone().add(new this.THREE.Vector3(horizontalLength * Math.cos(offsetAngle), horizontalLength * Math.sin(offsetAngle), 0));\n            let topPointTwo = bottomPointTwo.clone().add(new this.THREE.Vector3(0, heightRight, 0));\n\n            if (topPointOne.y.toFixed(2) != bottomPointOne.y.toFixed(2)) {\n              let newAxis = this.GraphicsThree3D.drawLine(bottomPointOne, topPointOne, lineProps);\n              newAxis.renderOrder = this.lineRenderOrder;\n              let newPointer = pointer.clone();\n              newPointer.position.add(bottomPointOne);\n              lineForceArrow.add(newPointer);\n              lineForceArrow.add(newAxis);\n            }\n\n            if (topPointTwo.y.toFixed(2) != bottomPointTwo.y.toFixed(2)) {\n              let newAxis = this.GraphicsThree3D.drawLine(bottomPointTwo, topPointTwo, lineProps);\n              newAxis.renderOrder = this.lineRenderOrder;\n              let newPointer = pointer.clone();\n              newPointer.position.add(bottomPointTwo);\n              lineForceArrow.add(newPointer);\n              lineForceArrow.add(newAxis);\n            }\n          }\n\n          for (let i = 0; i < horizontalDivisions + 1; i++) {\n            let bottomPoint = new this.THREE.Vector3(i * horizontalSegmentLength * Math.cos(offsetAngle), i * horizontalSegmentLength * Math.sin(offsetAngle), 0);\n            let topPoint = bottomPoint.clone().add(new this.THREE.Vector3(0, heightLeft - i * (heightLeft - heightRight) / horizontalDivisions, 0));\n\n            if (topPoint.y.toFixed(2) != bottomPoint.y.toFixed(2) && !(heightLeft && heightRight && (i == 0 || i == horizontalDivisions) && depthLength > 0 && depthDivisions == 0)) {\n              let newAxis = this.GraphicsThree3D.drawLine(bottomPoint, topPoint, lineProps);\n              newAxis.renderOrder = this.lineRenderOrder;\n              let newPointer = pointer.clone();\n              newPointer.position.add(bottomPoint);\n              lineForceArrow.add(newPointer);\n              lineForceArrow.add(newAxis);\n            }\n\n            if (depthLength > 0) {\n              let depthBottomPoint = bottomPoint.clone().add(new this.THREE.Vector3(0, 0, depthLength));\n              let depthTopPoint = topPoint.clone().add(new this.THREE.Vector3(0, 0, depthLength));\n\n              if (depthTopPoint.y.toFixed(2) != depthBottomPoint.y.toFixed(2) && !(heightLeft && heightRight && (i == 0 || i == horizontalDivisions) && depthDivisions == 0)) {\n                let newAxis = this.GraphicsThree3D.drawLine(depthBottomPoint, depthTopPoint, lineProps);\n                newAxis.renderOrder = this.lineRenderOrder;\n                let newPointer = pointer.clone();\n                newPointer.position.add(depthBottomPoint);\n                lineForceArrow.add(newPointer);\n                lineForceArrow.add(newAxis);\n              }\n            }\n          }\n        }\n      }\n\n      if (materialProps.textProps) {\n        this.addTextToArrow(materialProps.textProps, arrowData.components.texts, lineForceArrow, insertionProps.insertionPoint);\n      }\n\n      if (directionsDefined && areOrthogonal) {\n        let insertionPoint = new this.THREE.Vector3(0, 0, 0);\n\n        if (insertionProps.insertionPoint) {\n          insertionPoint.set(insertionProps.insertionPoint.x, insertionProps.insertionPoint.y, insertionProps.insertionPoint.z);\n        }\n\n        if (directionsDefined && areOrthogonal) this.GraphicsThree3D.alignObjectWithVectors(lineForceArrow, insertionPoint, dirVectorNormal, dirVectorHorizontal);\n      } else {\n        let insertionPoint = new this.THREE.Vector3(0, 0, 0);\n\n        if (insertionProps.insertionPoint) {\n          insertionPoint.set(insertionProps.insertionPoint.x, insertionProps.insertionPoint.y, insertionProps.insertionPoint.z);\n        }\n\n        lineForceArrow.position.add(insertionPoint);\n      }\n\n      this.addToDimChainCollisionDetection(lineForceArrow);\n      return lineForceArrow;\n    }\n\n    drawPointForceArrow(forceArrowData, headSize, height, materialProps, insertionProps, arrowData) {\n      let pointForceArrow = new this.THREE.Object3D();\n\n      if (forceArrowData.directionVector1 && (forceArrowData.directionVector1.x || forceArrowData.directionVector1.y || forceArrowData.directionVector1.z)) {\n        let directionVector = this.utils.initVector3(forceArrowData.directionVector1);\n        let pointerRadius = headSize.value2 / 2;\n        let pointerHeight = headSize.value1;\n        let volumeMaterial = this.getMaterialFromColor(materialProps.volumeProps.color);\n        let borderMaterial = this.getMaterialFromColor(materialProps.lineProps.color);\n        let pointer = this.makeArrow(pointerRadius, pointerHeight, volumeMaterial, borderMaterial, materialProps.lineProps);\n        pointer.rotation.z = Math.PI;\n        let axisHeight = height.value1;\n        let axisPointOne = new this.THREE.Vector3(0, 0, 0);\n        let axisPointTwo = new this.THREE.Vector3(0, axisHeight, 0);\n        let axis = this.GraphicsThree3D.drawLine(axisPointOne, axisPointTwo, materialProps.lineProps);\n        let arrow = new this.THREE.Object3D();\n        let arrowParts = new this.THREE.Object3D();\n        arrowParts.add(pointer);\n        arrowParts.add(axis);\n        arrow.add(arrowParts);\n        arrowParts.rotation.x = -Math.PI / 2;\n        arrow.lookAt(directionVector);\n        pointForceArrow.add(arrow);\n      }\n\n      pointForceArrow.position.set(insertionProps.insertionPoint.x, insertionProps.insertionPoint.y, insertionProps.insertionPoint.z);\n\n      if (materialProps.textProps) {\n        this.addTextToArrow(materialProps.textProps, arrowData.components.texts, pointForceArrow, insertionProps.insertionPoint);\n      }\n\n      this.addToDimChainCollisionDetection(pointForceArrow);\n      return pointForceArrow;\n    }\n\n    addTextToArrow(textProps, texts, object, objectInsertionPoint) {\n      if (textProps.type && textProps.style && textProps.color.alpha) {\n        let font = this.GraphicsThree3D.loadFont(textProps);\n\n        if (texts) {\n          texts.forEach(text => {\n            if (text.insertionPoint && text.directionVector && text.normalVector && (text.directionVector.x || text.directionVector.y || text.directionVector.z) && (text.normalVector.x || text.normalVector.y || text.normalVector.z) && text.content) {\n              let newText = this.GraphicsThree3D.drawText(text, textProps, font);\n\n              if (objectInsertionPoint) {\n                newText.position.sub(new this.THREE.Vector3(objectInsertionPoint.x, objectInsertionPoint.y, objectInsertionPoint.z));\n              }\n\n              object.add(newText);\n            }\n          });\n        }\n      }\n    }\n\n    getPlaneGeoFromPoints(points) {\n      let bottomPlaneGeo = new this.THREE.Geometry();\n      bottomPlaneGeo.vertices.push(...points);\n      bottomPlaneGeo.faces.push(new this.THREE.Face3(0, 1, 2), new this.THREE.Face3(0, 2, 3));\n      bottomPlaneGeo.faceVertexUvs[0].push([new this.THREE.Vector2(0, 0), new this.THREE.Vector2(1, 0), new this.THREE.Vector2(1, 1)], [new this.THREE.Vector2(0, 0), new this.THREE.Vector2(1, 1), new this.THREE.Vector2(0, 1)]);\n      bottomPlaneGeo.uvsNeedUpdate = true;\n      bottomPlaneGeo.computeFaceNormals();\n      bottomPlaneGeo.computeVertexNormals();\n      return bottomPlaneGeo;\n    }\n\n    getMaterialFromColor(color, isLine) {\n      let materialOptions = {\n        color: \"rgb(\" + color.red + \", \" + color.green + \", \" + color.blue + \")\",\n        polygonOffset: true,\n        polygonOffsetFactor: 1,\n        polygonOffsetUnits: 1,\n        transparent: true,\n        opacity: color.alpha / 255,\n        side: this.THREE.DoubleSide\n      };\n      let material = isLine ? new this.THREE.LineBasicMaterial(materialOptions) : new this.THREE.MeshBasicMaterial(materialOptions);\n      return material;\n    }\n\n    makeArrow(radius, height, areaMaterial, borderMaterial, lineProps, forArc = false) {\n      let localAreaMaterial = areaMaterial.clone();\n      localAreaMaterial.side = this.THREE.FrontSide;\n      let coneMesh, coneGeo, edgePts;\n\n      if (radius && height) {\n        coneGeo = new this.THREE.ConeGeometry(radius, height, 32);\n        coneGeo.translate(0, -height / 2, 0);\n        coneMesh = new this.THREE.Mesh(coneGeo, localAreaMaterial);\n        edgePts = coneGeo.vertices.slice(1, 33);\n        let line = this.utils.drawConnectedLines(edgePts, lineProps, true);\n        line.renderOrder = this.lineRenderOrder;\n        coneMesh.add(line);\n        let borderMesh;\n\n        if (lineProps.thickness && lineProps.color.alpha) {\n          let scale = 1 + lineProps.thickness / 4;\n          borderMesh = new this.THREE.Mesh(coneGeo, borderMaterial);\n          borderMesh.scale.multiplyScalar(scale);\n          borderMesh.material.side = this.THREE.BackSide;\n          borderMesh.position.y = (height - 1) * lineProps.thickness / 4;\n          coneMesh.add(borderMesh);\n          if (!forArc) coneMesh.position.y += 2 * lineProps.thickness;\n        }\n\n        let order = -99;\n        coneMesh.renderOrder = order;\n        if (borderMesh) borderMesh.renderOrder = order + 1;\n      } else coneMesh = new this.THREE.Mesh();\n\n      return coneMesh;\n    }\n\n  }\n\n  _exports.ArrowLoader = ArrowLoader;\n});","define(\"m08-2020/lib/FigureLoaders/DimensionalChainLoader\", [\"exports\", \"m08-2020/lib/Utils\", \"three-spritetext\"], function (_exports, _Utils, _threeSpritetext) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.DimensionalChainLoader = void 0;\n\n  class DimensionalChainLoader {\n    constructor(GraphicsThree3D) {\n      this.THREE = GraphicsThree3D.THREE;\n      this.fontUrlArray = GraphicsThree3D.fontUrlArray;\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.utils = new _Utils.Utils(GraphicsThree3D.THREE);\n      this.intersectionDetection = GraphicsThree3D.DimensionalChainIntersectionDetection; ///\n\n      this.drawMaskette = this.drawMaskette.bind(this);\n    }\n\n    drawDimensionalChains(dimensionalChains) {\n      if (dimensionalChains && dimensionalChains.length > 0 && !this.isOldDimChainJSON(dimensionalChains[0])) this.sortChainsByRank(dimensionalChains);\n      dimensionalChains.forEach(dimensionalChain => {\n        console.log(dimensionalChain);\n        let meshArray = this.drawMaskette(dimensionalChain);\n        meshArray.forEach(mesh => {\n          let drawnObject = new Object();\n          drawnObject.id = dimensionalChain.id;\n          drawnObject.type = \"maskette\";\n          drawnObject.data = dimensionalChain;\n          drawnObject.sceneObject = mesh;\n          drawnObject.isOnScene = mesh.IsHighLight ? false : true;\n          this.GraphicsThree3D.ThreeObjects.push(drawnObject);\n          if (!mesh.IsHighLight) this.GraphicsThree3D.scene.add(drawnObject.sceneObject);\n        });\n      });\n      this.intersectionDetection.chainArr = [];\n    }\n\n    sortChainsByRank(dimensionalChains) {\n      dimensionalChains.sort((a, b) => b.alignments.dimensionalChainArrangement.rankOrder - a.alignments.dimensionalChainArrangement.rankOrder);\n    }\n\n    isOldDimChainJSON(chainData) {\n      return chainData.alignments.view3d && chainData.alignments.view3d.hasOwnProperty(\"textAlignment\") || chainData.alignments.views2d && chainData.alignments.views2d[0].hasOwnProperty(\"textAlignment\");\n    }\n\n    drawMaskette(dimensionalChain, alignment2D = null) {\n      let meshArray = [];\n      let alignments = dimensionalChain.alignments;\n      let alignmentData = alignments.view3d;\n      let addToVisControl = true;\n\n      if (alignment2D) {\n        // addToVisControl = false;\n        alignmentData = { ...alignmentData,\n          ...alignment2D\n        };\n      }\n\n      if (this.isOldDimChainJSON(dimensionalChain)) {\n        alignments.textAlignment = alignmentData.textAlignment;\n        alignments.textArrangement = 2;\n        alignments.dimensionalChainArrangement = {\n          distance: 0,\n          rankOrder: 0,\n          type: 2\n        };\n      }\n\n      let alignmentOffset = alignmentData.offsetVector;\n      let insertionPoints = dimensionalChain.insertionPoints;\n\n      if (alignmentOffset && (alignmentOffset.x || alignmentOffset.y || alignmentOffset.z)) {\n        ///\n        if (alignments.dimensionalChainArrangement.type === 1) {\n          let chainType = this.getChainType(dimensionalChain);\n          let offsetVector = this.getChainOffsetVector(dimensionalChain, chainType, alignmentData);\n          alignmentOffset = {\n            x: offsetVector.x,\n            y: offsetVector.y,\n            z: offsetVector.z\n          };\n          alignmentData.offsetVector = alignmentOffset;\n        } ///\n\n\n        let chain = this.drawDimensionalChain(dimensionalChain, alignmentData);\n\n        if (chain) {\n          insertionPoints.forEach(insertionPoint => {\n            let insertionVector = insertionPoint.insertionVector;\n            let objectRotationAngle = insertionPoint.rotationAngle;\n            let chainObject = new this.THREE.Object3D();\n\n            if (objectRotationAngle) {\n              objectRotationAngle = objectRotationAngle * Math.PI / 180;\n              let rotationAxis = this.utils.initVector3(insertionPoint.rotationAxis);\n              let rotationPoint = this.utils.initVector3(insertionPoint.rotationPoint);\n              chainObject.position.copy(rotationPoint);\n              chainObject.attach(chain.clone());\n              chainObject.updateMatrix();\n              chainObject.rotateOnAxis(rotationAxis, objectRotationAngle);\n            } else chainObject.add(chain.clone());\n\n            chainObject.position.add(insertionVector);\n            if (addToVisControl) this.GraphicsThree3D.addObjectToVisControl(chainObject, \"dimensionalChain\");\n            meshArray.push(chainObject);\n          });\n        }\n      }\n\n      return meshArray;\n    }\n\n    drawDimensionalChain(dimensionalChain, alignmentData) {\n      let referencePoints = dimensionalChain.referencePoints; // Components\n\n      let hasBaseline = dimensionalChain.components.baseLine;\n      let baseLineOverhang = dimensionalChain.components.baseLineOverhang;\n      let endLine = dimensionalChain.components.endLine;\n      let endSymbol = dimensionalChain.components.endSymbol;\n      let texts = dimensionalChain.components.texts; // Alignment\n\n      let alignments = dimensionalChain.alignments;\n      let alignmentOffset = this.utils.initVector3(alignmentData.offsetVector); // Properties\n\n      let lineProps = dimensionalChain.properties.line;\n      let areaProps = dimensionalChain.properties.area;\n      let textProps = dimensionalChain.properties.text; // Materials\n\n      let areaMaterial = areaProps ? this.GraphicsThree3D.getMaterialFromColor(areaProps.color) : null;\n      if (areaMaterial) areaMaterial.side = this.THREE.FrontSide;\n      let chain = new this.THREE.Object3D();\n      let chainType = this.getChainType(dimensionalChain);\n\n      if (chainType === \"linear\") {\n        let startPoint = this.utils.initVector3(referencePoints[0]);\n        let endPoint = this.utils.initVector3(referencePoints[referencePoints.length - 1]);\n        let chainDirection = new this.THREE.Vector3().copy(endPoint).sub(startPoint).normalize();\n        let chainNormal = new this.THREE.Vector3().crossVectors(chainDirection, alignmentOffset.clone().normalize()).normalize();\n        let dx = endPoint.x - startPoint.x;\n        let dy = endPoint.y - startPoint.y; // baseLine\n\n        if (hasBaseline) {\n          let lineMesh = this.utils.drawConnectedLines([startPoint, endPoint], lineProps);\n          chain.add(lineMesh); ///\n          // console.log(startPoint, endPoint)\n\n          let lineForIntersection = this.utils.drawLine(startPoint, endPoint, lineProps); // lineForIntersection.geometry.computeBoundingBox();\n          // lineForIntersection.updateMatrix();\n          // console.log(lineForIntersection)\n\n          let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(lineForIntersection);\n          intersectionObjects.forEach(object => {\n            object.position.add(alignmentOffset);\n            object.updateMatrixWorld();\n          });\n          this.intersectionDetection.chainArr.push(intersectionObjects);\n        } // baseLineOverhang\n\n\n        if (baseLineOverhang && baseLineOverhang.position && baseLineOverhang.length) {\n          let overhangLength = baseLineOverhang.length;\n          let overhangPosition = baseLineOverhang.position;\n          let offset = new this.THREE.Vector3().copy(chainDirection).multiplyScalar(overhangLength);\n\n          if (overhangPosition === 1 || overhangPosition === 2) {\n            let overhangPoint = startPoint.clone().sub(offset);\n            let lineMesh = this.utils.drawConnectedLines([startPoint, overhangPoint], lineProps);\n            chain.add(lineMesh);\n          }\n\n          if (overhangPosition === 1 || overhangPosition === 3) {\n            let overhangPoint = endPoint.clone().add(offset);\n            let lineMesh = this.utils.drawConnectedLines([endPoint, overhangPoint], lineProps);\n            chain.add(lineMesh);\n          }\n        }\n\n        for (let i = 0; i < referencePoints.length - 1; i++) {\n          let referencePointOne = this.utils.initVector3(referencePoints[i]);\n          let referencePointTwo = this.utils.initVector3(referencePoints[i + 1]); // endLine\n\n          if (endLine) {\n            let offsetDir = this.utils.initVector3(alignmentOffset).normalize();\n            let lineMesh = this.drawEndLine(offsetDir, endLine, lineProps, referencePointOne);\n            chain.add(lineMesh);\n\n            if (i == referencePoints.length - 2) {\n              let lineMesh = this.drawEndLine(offsetDir, endLine, lineProps, referencePointTwo);\n              chain.add(lineMesh);\n            }\n          } // endSymbol\n\n\n          if (endSymbol) {\n            let endSymbolType = endSymbol.type;\n\n            if (endSymbolType === 1 && endSymbol.size) {\n              let circleRadius = endSymbol.size / 2;\n              let circle = this.drawEndSymbolCircle(circleRadius, areaMaterial, lineProps, chainNormal, referencePointOne);\n              chain.add(circle);\n\n              if (i == referencePoints.length - 2) {\n                let circle = this.drawEndSymbolCircle(circleRadius, areaMaterial, lineProps, chainNormal, referencePointTwo);\n                chain.add(circle);\n              }\n            } else if (endSymbolType === 2) {\n              let offsetDir = this.utils.initVector3(alignmentOffset).normalize();\n              let lineMesh = this.drawEndSymbolLine(offsetDir, chainNormal, referencePointOne, endSymbol, lineProps);\n              chain.add(lineMesh);\n\n              if (i == referencePoints.length - 2) {\n                let lineMesh = this.drawEndSymbolLine(offsetDir, chainNormal, referencePointTwo, endSymbol, lineProps);\n                chain.add(lineMesh);\n              }\n            } else if (endSymbolType === 3) {\n              let arrowRadius = endSymbol.size / 4;\n              let arrowLength = endSymbol.size;\n              let arrowOne = this.makeArrow(arrowRadius, arrowLength, areaMaterial, lineProps);\n              let arrowTwo = this.makeArrow(arrowRadius, arrowLength, areaMaterial, lineProps);\n              arrowOne.rotateOnWorldAxis(new this.THREE.Vector3(0, 0, 1), -Math.PI - Math.atan(dx / dy));\n              arrowTwo.rotateOnWorldAxis(new this.THREE.Vector3(0, 0, 1), -Math.atan(dx / dy));\n              arrowOne.position.add(referencePointOne);\n              arrowTwo.position.add(referencePointTwo);\n              chain.add(arrowOne);\n              chain.add(arrowTwo);\n            } else if (endSymbolType === 4) {\n              let arrowRadius = endSymbol.size / 2;\n              let arrowSize = endSymbol.size;\n              let arrow = this.makeArrow(arrowRadius, arrowSize, areaMaterial, lineProps);\n              arrow.rotateOnWorldAxis(new this.THREE.Vector3(0, 0, 1), -Math.atan(dx / dy));\n              arrow.position.add(referencePointOne);\n              chain.add(arrow);\n\n              if (i == referencePoints.length - 2) {\n                let arrowRadius = endSymbol.size / 2;\n                let arrowSize = endSymbol.size;\n                let arrow = this.makeArrow(arrowRadius, arrowSize, areaMaterial, lineProps);\n                arrow.rotateOnWorldAxis(new this.THREE.Vector3(0, 0, 1), -Math.atan(dx / dy));\n                arrow.position.add(referencePointTwo);\n                chain.add(arrow);\n              }\n            } else if (endSymbolType === 5) {\n              let arrowRadius = endSymbol.size / 2;\n              let arrowSize = endSymbol.size;\n              let arrow = this.makeArrow(arrowRadius, arrowSize, areaMaterial, lineProps);\n              arrow.rotateOnWorldAxis(new this.THREE.Vector3(0, 0, 1), -Math.PI - Math.atan(dx / dy));\n              arrow.position.add(referencePointOne);\n              chain.add(arrow);\n\n              if (i == referencePoints.length - 2) {\n                let arrowRadius = endSymbol.size / 2;\n                let arrowSize = endSymbol.size;\n                let arrow = this.makeArrow(arrowRadius, arrowSize, areaMaterial, lineProps);\n                arrow.rotateOnWorldAxis(new this.THREE.Vector3(0, 0, 1), -Math.PI - Math.atan(dx / dy));\n                arrow.position.add(referencePointTwo);\n                chain.add(arrow);\n              }\n            }\n          }\n        } // text\n\n\n        let canDrawText = this.canDrawText(dimensionalChain);\n\n        if (canDrawText) {\n          let font = this.GraphicsThree3D.loadFont(textProps);\n\n          if (alignments.textAlignment === 1) {\n            for (let text of texts) {\n              let textInsideChain = this.textInsideChain(text, startPoint, endPoint, chainDirection);\n\n              if (textInsideChain) {\n                let textInsertionPoint = text.insertionPoint;\n                let textContent = text.content;\n                let textOffset = text.offset;\n                let pointsDir = new this.THREE.Vector3().subVectors(endPoint, startPoint).normalize();\n                let offsetDir = this.utils.initVector3(alignmentOffset).normalize();\n                let crossPointsOffset = new this.THREE.Vector3().crossVectors(pointsDir, offsetDir);\n                let textOffsetDir = new this.THREE.Vector3().crossVectors(crossPointsOffset, pointsDir).normalize();\n                let textPosition = this.utils.initVector3(textInsertionPoint);\n                textPosition.add(textOffsetDir.multiplyScalar(textOffset));\n                let textMesh = this.makeTextSprite(textContent, textPosition, textProps);\n                chain.add(textMesh);\n              }\n            }\n          } else if (alignments.textAlignment === 2 && alignmentData.normalVector && alignmentData.directionVector) {\n            let textDataArr = [];\n            let tempIntersectionTexts = [];\n            let isIntersection = false;\n\n            for (let text of texts) {\n              let textInsideChain = this.textInsideChain(text, startPoint, endPoint, chainDirection);\n\n              if (textInsideChain) {\n                let textInsertionPoint = text.insertionPoint;\n                let textOffset = text.offset;\n                let pointsDir = new this.THREE.Vector3().subVectors(endPoint, startPoint).normalize();\n                let offsetDir = this.utils.initVector3(alignmentOffset).normalize();\n                let crossPointsOffset = new this.THREE.Vector3().crossVectors(pointsDir, offsetDir);\n                let textOffsetDir = new this.THREE.Vector3().crossVectors(crossPointsOffset, pointsDir).normalize();\n                let textPosition = this.utils.initVector3(textInsertionPoint);\n                textPosition.add(textOffsetDir.multiplyScalar(textOffset));\n                let textData = {\n                  content: text.content,\n                  id: text.id,\n                  insertionPoint: textPosition,\n                  offset: text.offset,\n                  normalVector: alignmentData.normalVector,\n                  directionVector: alignmentData.directionVector\n                }; ///\n\n                let normalVector = this.utils.initVector3(alignmentData.normalVector);\n                let directionVector = this.utils.initVector3(alignmentData.directionVector);\n\n                if (!normalVector.dot(directionVector) && normalVector.lengthSq() && directionVector.lengthSq()) {\n                  let offsetVec = this.utils.initVector3(alignmentOffset);\n                  textData.negativeOffset = textOffsetDir.clone().normalize().multiplyScalar(2 * textData.offset);\n                  let [box, linePoints] = this.makeTextBoxWithLines(textData, textProps, font);\n                  box.position.add(offsetVec);\n\n                  if (alignments.textAlignment === 2 && alignments.textArrangement === 1) {\n                    let linePtsArr = [];\n                    linePoints.forEach(point => point.add(offsetVec));\n\n                    for (let i = 0; i < linePoints.length - 1; i++) linePtsArr.push([linePoints[i], linePoints[i + 1]]);\n\n                    isIntersection = this.intersectionDetection.checkCollision(linePtsArr, tempIntersectionTexts);\n                    let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(box);\n                    tempIntersectionTexts.push(intersectionObjects);\n                  }\n\n                  textDataArr.push({\n                    textData,\n                    box\n                  });\n                }\n              }\n            }\n\n            for (let i = 0; i < textDataArr.length; i++) {\n              let textData = textDataArr[i].textData;\n              let box = textDataArr[i].box;\n\n              if (isIntersection && alignments.textAlignment === 2 && alignments.textArrangement === 1) {\n                textData.offset = textDataArr[0].textData.offset;\n\n                if (i % 2 === 1) {\n                  textData.insertionPoint.sub(textData.negativeOffset);\n                  box.position.sub(textData.negativeOffset);\n                }\n              }\n\n              let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(box);\n              this.intersectionDetection.chainArr.push(intersectionObjects);\n              let textMesh = this.GraphicsThree3D.drawText(textData, textProps, font);\n              chain.add(textMesh);\n            }\n          }\n        }\n\n        chain.position.add(this.utils.initVector3(alignmentOffset));\n      } else if (chainType === \"arc\") {\n        let centerPoint = this.utils.initVector3(dimensionalChain.referencePoints[0]);\n        let arcRadius = alignmentOffset.length(); // baseLine\n\n        let rotationAngle = dimensionalChain.shape.rotationAngle;\n        let rotationAxis = new this.THREE.Vector3(0, 0, 1);\n        let shapeAxis = this.utils.initVector3(dimensionalChain.shape.rotationAxis).normalize();\n        let quaternion = new this.THREE.Quaternion().setFromUnitVectors(shapeAxis, rotationAxis);\n        alignmentOffset.applyQuaternion(quaternion);\n        let offsetVectorNormalized = alignmentOffset.clone().normalize();\n        let startAngle = -Math.acos(offsetVectorNormalized.x) + this.GraphicsThree3D.degreeToRadians(rotationAngle);\n        let endAngle = -Math.acos(offsetVectorNormalized.x);\n        let isClockwise = rotationAngle > 0;\n        let curve = new this.THREE.EllipseCurve(0, 0, arcRadius, arcRadius, startAngle, endAngle, isClockwise ? true : false, 0);\n        let curvePoints = curve.getPoints(50).map(point => new this.THREE.Vector3(point.x, point.y, 0));\n\n        if (hasBaseline) {\n          let ellipse = this.utils.drawConnectedLines(curvePoints, lineProps);\n          chain.add(ellipse); ///\n\n          let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(ellipse);\n          intersectionObjects.forEach(object => {\n            object.lookAt(shapeAxis);\n            object.position.add(centerPoint);\n            object.updateMatrixWorld();\n          });\n          this.intersectionDetection.chainArr.push(intersectionObjects);\n        }\n\n        let pseudoReferencePoints = [curvePoints[0], curvePoints[curvePoints.length - 1]];\n        pseudoReferencePoints.forEach((pseudoReferencePoint, i) => {\n          // baseLineOverhang\n          if (baseLineOverhang && baseLineOverhang.position) {\n            let overhangLength = baseLineOverhang.length;\n            let overHangPosition = baseLineOverhang.position;\n            let pivotPoint = new this.THREE.Vector3(0, 0, 0);\n            let overhangPoint;\n\n            if (overHangPosition == 1) {\n              overhangPoint = new this.THREE.Vector3(i == 0 ? overhangLength : -overhangLength, 0, 0);\n            } else if (overHangPosition == 2) {\n              overhangPoint = new this.THREE.Vector3(i == 0 ? 0 : -overhangLength, 0, 0);\n            } else if (overHangPosition == 3) {\n              overhangPoint = new this.THREE.Vector3(i == 0 ? overhangLength : 0, 0, 0);\n            }\n\n            if (!pivotPoint.equals(overhangPoint)) {\n              let lineMesh = this.utils.drawConnectedLines([pivotPoint, overhangPoint], lineProps);\n              lineMesh.rotateOnAxis(rotationAxis, i == 0 ? Math.PI / 2 + startAngle : Math.PI / 2 + endAngle);\n              if (rotationAngle < 0) lineMesh.rotateOnAxis(rotationAxis, Math.PI);\n              lineMesh.position.copy(pseudoReferencePoint);\n              chain.add(lineMesh);\n            }\n          } // endLine\n\n\n          if (endLine) {\n            let offsetDir = offsetVectorNormalized.clone();\n            if (i === 0) offsetDir.applyAxisAngle(rotationAxis, this.GraphicsThree3D.degreeToRadians(rotationAngle));\n            let lineMesh = this.drawEndLine(offsetDir, endLine, lineProps, pseudoReferencePoint);\n            chain.add(lineMesh);\n          } // endSymbol\n\n\n          if (endSymbol) {\n            let endSymbolType = endSymbol.type;\n\n            if (endSymbolType === 1 && endSymbol.size) {\n              let circleRadius = endSymbol.size / 2;\n              let circle = this.makeCircleWithEdges(circleRadius, areaMaterial, lineProps);\n              circle.position.copy(pseudoReferencePoint);\n              chain.add(circle);\n            } else if (endSymbolType === 2) {\n              let offsetDir = offsetVectorNormalized.clone();\n              if (i === 0) offsetDir.applyAxisAngle(rotationAxis, this.GraphicsThree3D.degreeToRadians(rotationAngle));\n              let lineMesh = this.drawEndSymbolLine(offsetDir, rotationAxis, pseudoReferencePoint, endSymbol, lineProps, true);\n              chain.add(lineMesh);\n            } else if (endSymbolType === 3) {\n              let arrowRadius = endSymbol.size / 4;\n              let arrowLength = endSymbol.size;\n              let arrowMesh = this.makeArrow(arrowRadius, arrowLength, areaMaterial, lineProps);\n              arrowMesh.rotateOnAxis(rotationAxis, i == 0 ? startAngle : Math.PI + endAngle);\n              arrowMesh.position.copy(pseudoReferencePoint);\n              chain.add(arrowMesh);\n            } else if (endSymbolType === 4) {\n              let arrowRadius = endSymbol.size / 2;\n              let arrowSize = endSymbol.size;\n              let arrowMesh = this.makeArrow(arrowRadius, arrowSize, areaMaterial, lineProps);\n              arrowMesh.rotateOnAxis(rotationAxis, i == 0 ? startAngle : endAngle);\n              arrowMesh.position.copy(pseudoReferencePoint);\n              chain.add(arrowMesh);\n            } else if (endSymbolType === 5) {\n              let arrowRadius = endSymbol.size / 2;\n              let arrowSize = endSymbol.size;\n              let arrowMesh = this.makeArrow(arrowRadius, arrowSize, areaMaterial, lineProps);\n              arrowMesh.rotateOnAxis(rotationAxis, i == 0 ? Math.PI + startAngle : Math.PI + endAngle);\n              arrowMesh.position.copy(pseudoReferencePoint);\n              chain.add(arrowMesh);\n            }\n          }\n        }); // text\n\n        let canDrawText = this.canDrawText(dimensionalChain);\n\n        if (canDrawText) {\n          let font = this.GraphicsThree3D.loadFont(textProps);\n\n          for (let i = 0; i < texts.length; i++) {\n            let textContent = texts[i].content;\n            let textInsertionPoint = texts[i].insertionPoint;\n            let referencePoint = dimensionalChain.referencePoints[0];\n\n            if (textContent && textInsertionPoint && this.utils.checkVectorsEquality(textInsertionPoint, referencePoint)) {\n              let textOffset = texts[i].offset;\n              let offsetDir = new this.THREE.Vector3().copy(alignmentOffset);\n              offsetDir.applyAxisAngle(rotationAxis, this.GraphicsThree3D.degreeToRadians(rotationAngle / 2));\n              let textPosition = new this.THREE.Vector3().copy(offsetDir);\n              offsetDir = offsetDir.normalize();\n              textPosition.add(offsetDir.multiplyScalar(textOffset));\n\n              if (alignments.textAlignment === 1) {\n                let textMesh = this.makeTextSprite(textContent, textPosition, textProps);\n                chain.add(textMesh);\n              } else if (alignments.textAlignment === 2 && alignmentData.normalVector && alignmentData.directionVector) {\n                let textData = {\n                  content: texts[i].content,\n                  id: texts[i].id,\n                  insertionPoint: textPosition,\n                  offset: texts[i].offset,\n                  normalVector: alignmentData.normalVector,\n                  directionVector: alignmentData.directionVector\n                };\n                let textMesh = this.GraphicsThree3D.drawText(textData, textProps, font);\n                chain.add(textMesh); ///\n\n                let normalVector = this.utils.initVector3(alignmentData.normalVector);\n                let directionVector = this.utils.initVector3(alignmentData.directionVector);\n\n                if (!normalVector.dot(directionVector) && normalVector.lengthSq() && directionVector.lengthSq()) {\n                  let [box, linePoints] = this.makeTextBoxWithLines(textData, textProps, font);\n                  let pivotObj = new this.THREE.Object3D();\n                  pivotObj.attach(box);\n                  pivotObj.lookAt(shapeAxis);\n                  pivotObj.position.add(centerPoint);\n                  pivotObj.updateMatrixWorld();\n                  pivotObj.children.forEach(child => child.applyMatrix4(pivotObj.matrixWorld));\n                  let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(box);\n                  this.intersectionDetection.chainArr.push(intersectionObjects);\n                }\n              }\n            }\n          }\n        }\n\n        chain.lookAt(shapeAxis);\n        chain.position.add(centerPoint);\n      }\n\n      return chain;\n    }\n\n    makeTextBoxWithLines(text, textProps, font) {\n      let normalVector = this.utils.initVector3(text.normalVector);\n      let directionVector = this.utils.initVector3(text.directionVector);\n      let textInsertionPoint = text.insertionPoint;\n      let textGeo = this.makeTextGeoLight(text, textProps, font);\n      textGeo.computeBoundingBox();\n      let bboxMax = textGeo.boundingBox.max;\n      let bboxMin = textGeo.boundingBox.min;\n      let linePoints = [new this.THREE.Vector3(bboxMin.x, bboxMax.y, 0), new this.THREE.Vector3(bboxMin.x, bboxMin.y, 0), new this.THREE.Vector3(bboxMax.x, bboxMin.y, 0), new this.THREE.Vector3(bboxMax.x, bboxMax.y, 0)];\n      let boxWidth = bboxMax.x - bboxMin.x;\n      let boxHeight = bboxMax.y - bboxMin.y;\n      let boxDepth = 0.1;\n      let textMaterial = new this.THREE.MeshBasicMaterial({\n        color: 0xff0000\n      });\n      let boxGeometry = new this.THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);\n      let textMeshBox = new this.THREE.Mesh(boxGeometry, textMaterial);\n      this.GraphicsThree3D.alignObjectWithVectors(textMeshBox, textInsertionPoint, normalVector, directionVector);\n      textMeshBox.updateMatrix();\n      linePoints.forEach(point => point.applyMatrix4(textMeshBox.matrix));\n      return [textMeshBox, linePoints];\n    }\n\n    textInsideChain(textData, startPoint, endPoint, chainDirection) {\n      const TOLERANCE = 0.0001;\n      let textInsertionPoint = textData.insertionPoint;\n      let textContent = textData.content;\n      let insideChain;\n\n      if (textInsertionPoint) {\n        let textInsertionVector = this.utils.initVector3(textInsertionPoint);\n        let insertionLength = textInsertionVector.length();\n        textInsertionVector.sub(startPoint).normalize();\n        insideChain = textContent && this.utils.initVector3(textInsertionPoint).distanceTo(startPoint) <= endPoint.distanceTo(startPoint) && (chainDirection.dot(textInsertionVector) > 1 - TOLERANCE || !textInsertionVector.length());\n        if (!insideChain) console.log(insertionLength);\n      }\n\n      return insideChain;\n    }\n\n    canDrawText(chainData) {\n      let texts = chainData.components.texts;\n      let alignments = chainData.alignments;\n      let textProps = chainData.properties.text;\n      return texts && textProps.type && textProps.style && alignments.textAlignment && alignments.textArrangement && textProps.size && textProps.heightWidthRatio;\n    }\n\n    makeTextGeoLight(text, textProps, font) {\n      let textContent = text.content;\n      let fontSize = textProps.size;\n      let heightWidthRatio = textProps.heightWidthRatio;\n      let textGeo = new this.THREE.TextBufferGeometry(textContent, {\n        font: font,\n        size: fontSize,\n        height: 0.1,\n        curveSegments: 1\n      });\n      textGeo.scale(heightWidthRatio, 1, 1);\n      textGeo.center();\n      return textGeo;\n    }\n\n    drawEndLine(offsetDir, lineData, lineProps, linePos) {\n      let [ptOne, ptTwo] = this.getEndLinePts(lineData, offsetDir);\n      let lineMesh = this.utils.drawConnectedLines([ptOne, ptTwo], lineProps);\n      lineMesh.position.add(linePos);\n      return lineMesh;\n    }\n\n    getEndLinePts(lineData, offsetDir) {\n      let length = lineData.lenght;\n      let overhang = lineData.overhang;\n      length *= -1;\n      console.log(lineData, offsetDir);\n      let ptOne = offsetDir.clone().multiplyScalar(length);\n      let ptTwo = offsetDir.clone().multiplyScalar(overhang);\n      return [ptOne, ptTwo];\n    }\n\n    drawEndSymbolCircle(radius, areaMaterial, lineProps, normal, position) {\n      let circle = this.makeCircleWithEdges(radius, areaMaterial, lineProps);\n      circle.lookAt(normal);\n      circle.position.copy(position);\n      return circle;\n    }\n\n    drawEndSymbolLine(offsetDir, normalVector, linePos, symbolData, lineProps, forArc = false) {\n      let lineSize = symbolData.size;\n      let ptOne = offsetDir.clone().multiplyScalar(lineSize / 2);\n      let ptTwo = offsetDir.clone().multiplyScalar(-lineSize / 2);\n      let rotation = Math.PI / 4;\n      if (forArc) rotation *= -1;\n      ptOne.applyAxisAngle(normalVector, rotation);\n      ptTwo.applyAxisAngle(normalVector, rotation);\n      let lineMesh = this.utils.drawConnectedLines([ptOne, ptTwo], lineProps);\n      lineMesh.position.add(linePos);\n      return lineMesh;\n    }\n\n    makeArrow(radius, height, areaMaterial, lineProps) {\n      let arrowMesh;\n\n      if (areaMaterial) {\n        let pts = [new this.THREE.Vector2(0, 0), new this.THREE.Vector2(-radius, -height), new this.THREE.Vector2(radius, -height)];\n        let arrowShape = new this.THREE.Shape(pts);\n        let arrowGeo = new this.THREE.ExtrudeBufferGeometry(arrowShape, {\n          depth: 0.1,\n          bevelEnabled: false\n        });\n        arrowGeo.translate(0, 0, -0.05);\n        arrowMesh = new this.THREE.Mesh(arrowGeo, areaMaterial);\n        let linePoints = pts.map(point => new this.THREE.Vector3(point.x, point.y, 0));\n        let line = this.utils.drawConnectedLines(linePoints, lineProps, true);\n        arrowMesh.add(line);\n        arrowMesh.renderOrder = 1;\n      } else {\n        arrowMesh = new this.THREE.Mesh(); // TODO: Might need better solution\n      }\n\n      return arrowMesh;\n    }\n\n    makeCircleWithEdges(radius, areaMaterial, lineProps, customParameters = null) {\n      let circleGeo;\n\n      if (customParameters) {\n        let thetaStart = customParameters.thetaStart;\n        let thetaEnd = customParameters.thetaEnd;\n        circleGeo = new this.THREE.CircleGeometry(radius, 32, thetaStart, thetaEnd);\n        let radiusTwo = customParameters.radiusTwo;\n        circleGeo.applyMatrix4(new this.THREE.Matrix4().makeScale(1, radiusTwo / radius, 1));\n      } else {\n        circleGeo = new this.THREE.CircleGeometry(radius, 32);\n      }\n\n      let areaMesh = new this.THREE.Mesh(circleGeo, areaMaterial);\n      let linePts = circleGeo.vertices.slice(1);\n      let line = this.utils.drawConnectedLines(linePts, lineProps, true);\n      areaMesh.add(line);\n      return areaMesh;\n    }\n\n    makeTextSprite(textContent, textPosition, textProps) {\n      let textColor = \"rgba(\" + textProps.color.red + \", \" + textProps.color.green + \", \" + textProps.color.blue + \", \" + textProps.color.alpha + \")\";\n      let textMesh = new _threeSpritetext.default(textContent);\n      textMesh.fontSize = 100;\n      textMesh.textHeight = textProps.size;\n      textMesh.geometry.scale(textProps.heightWidthRatio, 1, 1);\n      textMesh.color = textColor;\n      textMesh.renderOrder = 1;\n      if (textProps.type == 1) textMesh.fontFace = \"Arial\";else if (textProps.type == 2) textMesh.fontFace = \"Calibri\";else if (textProps.type == 3) textMesh.fontFace = \"Courier\";else if (textProps.type == 4) textMesh.fontFace = \"TimesNewRoman\";\n\n      if (textProps.style == 2 || textProps.style == 4) {\n        textMesh.geometry.applyMatrix4(new this.THREE.Matrix4().set(1, 0.1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1));\n      }\n\n      if (textProps.style == 3 || textProps.style == 4) {\n        textMesh.fontWeight = \"bold\";\n      }\n\n      textMesh.position.copy(textPosition);\n      return textMesh;\n    }\n\n    getChainType(dimensionalChain) {\n      let typeOfChain = dimensionalChain.shape.type;\n      let referencePoints = dimensionalChain.referencePoints;\n      if (typeOfChain === 1 && referencePoints.length >= 2) return \"linear\";else if (typeOfChain === 2 && dimensionalChain.referencePoints.length === 1 && dimensionalChain.shape.rotationAngle && dimensionalChain.shape.rotationAxis && (dimensionalChain.shape.rotationAxis.x || dimensionalChain.shape.rotationAxis.y || dimensionalChain.shape.rotationAxis.z)) return \"arc\";\n    }\n\n    getChainOffsetVector(chainData, chainType, alignmentData) {\n      let initOffset = alignmentData.offsetVector;\n      let offsetDir = this.utils.initVector3(initOffset).normalize();\n      let distance = chainData.alignments.dimensionalChainArrangement.distance;\n      let offsetDistance = new this.THREE.Vector3().copy(offsetDir).multiplyScalar(distance);\n      let offsetVector = new this.THREE.Vector3().copy(offsetDistance);\n      let meshArr = this.intersectionDetection.meshArr;\n      let chainArr = this.intersectionDetection.chainArr;\n      let isIntersection;\n\n      do {\n        isIntersection = false;\n        let linePtsArr = [];\n\n        if (chainType === \"linear\") {\n          let startPoint = this.utils.initVector3(chainData.referencePoints[0]).add(offsetVector);\n          let endPoint = this.utils.initVector3(chainData.referencePoints[chainData.referencePoints.length - 1]).add(offsetVector);\n          linePtsArr.push([startPoint, endPoint]);\n        } else {\n          let curvePoints = this.generateArcPoints(chainData, offsetVector);\n\n          for (let i = 0; i < curvePoints.length - 1; i++) linePtsArr.push([curvePoints[i], curvePoints[i + 1]]);\n        } ///\n\n\n        let texts = chainData.components.texts;\n        let textProps = chainData.properties.text;\n        let referencePoints = chainData.referencePoints;\n        let canDrawText = this.canDrawText(chainData);\n        let font = canDrawText ? this.GraphicsThree3D.loadFont(textProps) : null;\n\n        if (chainData.alignments.textAlignment === 2) {\n          if (chainType === \"linear\") {\n            let startPoint = this.utils.initVector3(referencePoints[0]);\n            let endPoint = this.utils.initVector3(referencePoints[referencePoints.length - 1]);\n            let chainDirection = new this.THREE.Vector3().copy(endPoint).sub(startPoint).normalize();\n\n            if (canDrawText) {\n              texts.forEach(text => {\n                let textInsideChain = this.textInsideChain(text, startPoint, endPoint, chainDirection);\n\n                if (textInsideChain) {\n                  let textInsertionPoint = text.insertionPoint;\n                  let textOffset = text.offset;\n                  let pointsDir = new this.THREE.Vector3().subVectors(endPoint, startPoint).normalize();\n                  let offsetDir = this.utils.initVector3(initOffset).normalize();\n                  let crossPointsOffset = new this.THREE.Vector3().crossVectors(pointsDir, offsetDir);\n                  let textOffsetDir = new this.THREE.Vector3().crossVectors(crossPointsOffset, pointsDir).normalize();\n                  let textPosition = this.utils.initVector3(textInsertionPoint);\n                  textPosition.add(textOffsetDir.multiplyScalar(textOffset));\n                  let textData = {\n                    content: text.content,\n                    id: text.id,\n                    insertionPoint: textPosition,\n                    offset: text.offset,\n                    normalVector: alignmentData.normalVector,\n                    directionVector: alignmentData.directionVector\n                  };\n                  let [box, linePoints] = this.makeTextBoxWithLines(textData, textProps, font);\n                  linePoints.forEach(point => point.add(offsetVector));\n\n                  for (let i = 0; i < linePoints.length - 1; i++) linePtsArr.push([linePoints[i], linePoints[i + 1]]);\n                }\n              });\n            }\n          } else {\n            let rotationAxis = this.utils.initVector3(chainData.shape.rotationAxis);\n            let rotationAngle = chainData.shape.rotationAngle;\n            let centerPoint = this.utils.initVector3(chainData.referencePoints[0]);\n\n            if (canDrawText) {\n              texts.forEach(text => {\n                let textContent = text.content;\n                let textInsertionPoint = text.insertionPoint;\n                let referencePoint = chainData.referencePoints[0];\n\n                if (textContent && textInsertionPoint && this.utils.checkVectorsEquality(textInsertionPoint, referencePoint)) {\n                  let textOffset = text.offset;\n                  let offsetDir = new this.THREE.Vector3().copy(offsetVector);\n                  offsetDir.applyAxisAngle(rotationAxis, this.GraphicsThree3D.degreeToRadians(rotationAngle / 2));\n                  let textPosition = new this.THREE.Vector3().copy(offsetDir);\n                  offsetDir = offsetDir.normalize();\n                  textPosition.add(offsetDir.multiplyScalar(textOffset));\n                  let textData = {\n                    content: text.content,\n                    id: text.id,\n                    insertionPoint: textPosition,\n                    offset: text.offset,\n                    normalVector: alignmentData.normalVector,\n                    directionVector: alignmentData.directionVector\n                  };\n                  let [box, linePoints] = this.makeTextBoxWithLines(textData, textProps, font);\n                  linePoints.forEach(point => point.add(centerPoint));\n\n                  for (let i = 0; i < linePoints.length - 1; i++) linePtsArr.push([linePoints[i], linePoints[i + 1]]);\n                }\n              });\n            }\n          }\n        } ///\n\n\n        isIntersection = this.intersectionDetection.checkCollision(linePtsArr, meshArr) || this.intersectionDetection.checkCollision(linePtsArr, chainArr);\n        if (isIntersection) offsetVector.add(offsetDistance);\n      } while (isIntersection);\n\n      return offsetVector;\n    }\n\n    generateArcPoints(chainData, alignmentOffset) {\n      const DETAIL = 64;\n      let offsetVector = alignmentOffset.clone();\n      let arcRadius = offsetVector.length();\n      let rotationAngle = chainData.shape.rotationAngle;\n      let rotationAxis = new this.THREE.Vector3(0, 0, 1);\n      let shapeAxis = this.utils.initVector3(chainData.shape.rotationAxis).normalize();\n      let quaternion = new this.THREE.Quaternion().setFromUnitVectors(shapeAxis, rotationAxis);\n      offsetVector.applyQuaternion(quaternion);\n      let offsetVectorNormalized = offsetVector.clone().normalize();\n      let startAngle = -Math.acos(offsetVectorNormalized.x) + this.GraphicsThree3D.degreeToRadians(rotationAngle);\n      let endAngle = -Math.acos(offsetVectorNormalized.x);\n      let isClockwise = rotationAngle > 0;\n      let curve = new this.THREE.EllipseCurve(0, 0, arcRadius, arcRadius, startAngle, endAngle, isClockwise ? true : false, 0);\n      let numOfPoints = DETAIL * rotationAngle / 360;\n      let curvePoints = curve.getPoints(numOfPoints).map(point => new this.THREE.Vector3(point.x, point.y, 0));\n      quaternion.conjugate();\n      curvePoints.forEach(point => {\n        point.applyQuaternion(quaternion);\n        point.add(this.utils.initVector3(chainData.referencePoints[0]));\n      });\n      return curvePoints;\n    }\n\n  }\n\n  _exports.DimensionalChainLoader = DimensionalChainLoader;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingObjectComponents/ComplexVolume\", [\"exports\", \"m08-2020/lib/Utils/BooleanOperations\"], function (_exports, BooleanOperations) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.ComplexVolume = void 0;\n\n  class ComplexVolume {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.THREE = GraphicsThree3D.THREE;\n      this.utils = GraphicsThree3D.utils;\n      this.CSG = GraphicsThree3D.CSG;\n      this.WireframeGenerator = GraphicsThree3D.WireframeGenerator;\n    }\n\n    addMultilayeredObjectsToScene(multilayeredObjects, wireframes, properties, insertionPoints, jsonData, drawingObject) {\n      let meshArr = [];\n      let positives = [];\n      let negatives = [];\n      multilayeredObjects.positives.forEach(objData => {\n        let [geometry, faceSideNormal, grainDirection, midVector, eulerTwo] = objData;\n        let mesh = new this.THREE.Mesh(geometry);\n        mesh.position.add(midVector);\n        mesh.setRotationFromEuler(eulerTwo);\n        mesh.updateMatrix();\n        positives.push([mesh, faceSideNormal, grainDirection]);\n      });\n      multilayeredObjects.negatives.forEach(objData => {\n        let [geometry, faceSideNormal, grainDirection, midVector, eulerTwo] = objData;\n        let mesh = new this.THREE.Mesh(geometry);\n        mesh.position.add(midVector);\n        mesh.setRotationFromEuler(eulerTwo);\n        mesh.updateMatrix();\n        negatives.push(mesh);\n      });\n      positives.forEach(positive => negatives.forEach(negative => positive[0] = BooleanOperations.doCSG(positive[0], negative, \"subtract\")));\n      positives.forEach(posData => {\n        let [mesh, faceSideNormal, grainDirection] = posData;\n        this.GraphicsThree3D.indexVolumeFaces(mesh.geometry, faceSideNormal, grainDirection);\n        let materials = this.GraphicsThree3D.getVolumeMaterials(properties.volume.color);\n        mesh.material = materials;\n        meshArr.push(mesh);\n      });\n      meshArr.forEach(mesh => this.GraphicsThree3D.DrawingObjectLoader.addToDimChainCollisionDetection(mesh, insertionPoints));\n      meshArr.forEach(mesh => {\n        let transparentMesh = new this.THREE.Mesh();\n        transparentMesh.applyMatrix4(mesh.matrix);\n        this.WireframeGenerator.applyWireframesArea(mesh, transparentMesh, properties.line, drawingObject); // TODO: Change to volume wireframe function\n\n        this.GraphicsThree3D.addObjectToScene(mesh, transparentMesh, insertionPoints, jsonData, \"volume\", \"drawingObject\", drawingObject);\n      });\n    }\n\n    generateBBoxDepthAndPoints(geometry) {\n      const SIZE_DELTA = 1;\n      geometry.computeBoundingBox();\n      let bbox = geometry.boundingBox;\n      let bboxDepth = (bbox.max.z - bbox.min.z + SIZE_DELTA) * 2;\n      let pts = [new this.THREE.Vector3(bbox.min.x - SIZE_DELTA, bbox.min.y - SIZE_DELTA, 0), new this.THREE.Vector3(bbox.max.x + SIZE_DELTA, bbox.min.y - SIZE_DELTA, 0), new this.THREE.Vector3(bbox.max.x + SIZE_DELTA, bbox.max.y + SIZE_DELTA, 0), new this.THREE.Vector3(bbox.min.x - SIZE_DELTA, bbox.max.y + SIZE_DELTA, 0)].map(pt => pt.multiplyScalar(2));\n      return [bboxDepth, pts];\n    }\n\n    makeExtrudedMeshForCSG(points2D, depth) {\n      let rawGeo = this.GraphicsThree3D.makePositionedExtrusion({\n        points2D,\n        depth,\n        translation: [0, 0, 0],\n        skew: [0, 0]\n      });\n      let mesh = new this.THREE.Mesh(rawGeo);\n      return mesh;\n    }\n\n    drawMultilayeredEllipses(ellipses, properties, multilayeredObjects) {\n      let wireframes = [];\n      ellipses.forEach(ellipse => {\n        console.log(ellipse);\n\n        if (ellipse.objectGeneration.type === 3) {\n          let ellipseMesh = this.GraphicsThree3D.DrawingObjectLoader.Ellipse.drawEllipse(ellipse, properties);\n          let [bboxDepth, pts] = this.generateBBoxDepthAndPoints(ellipseMesh.geometry);\n          let extrusionVector = new this.THREE.Vector3(0, 0, bboxDepth);\n          let centerPoint = this.utils.initVector3(ellipse.centerPoint);\n          ellipseMesh.updateMatrix();\n          pts.forEach(pt => pt.sub(centerPoint));\n\n          if (properties.volume.type === 2) {\n            let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n            let grainDirection = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n            let segments = this.segmentPointsVertical(pts, properties.volume);\n            segments.forEach(pointArr => {\n              let rawMesh = this.makeExtrudedMeshForCSG(pointArr, bboxDepth);\n              let modifiedMesh = BooleanOperations.doCSG(ellipseMesh, rawMesh, \"intersect\");\n              let geometry = modifiedMesh.geometry;\n              this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipseMesh.rotation]);\n            });\n          } else if (properties.volume.type === 3) {\n            let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n            let grainDirectionOne = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n            let grainDirectionTwo = this.utils.initVector3(properties.volume.layers[1].grainDirectionVector).normalize();\n            let grainDirection;\n            let segments = this.segmentPointsVertical(pts, properties.volume);\n            segments.forEach(pointArr => {\n              grainDirection = pointArr.type ? grainDirectionOne : grainDirectionTwo;\n              let rawMesh = this.makeExtrudedMeshForCSG(pointArr.points, bboxDepth);\n              let modifiedMesh = BooleanOperations.doCSG(ellipseMesh, rawMesh, \"intersect\");\n              let geometry = modifiedMesh.geometry;\n              this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipseMesh.rotation]);\n            });\n          } else if (properties.volume.type === 4) {\n            let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n            let segments = this.segmentPointsVertical(pts, properties.volume);\n\n            for (let i = 0; i < segments.length; i++) {\n              let segment = segments[i];\n              let layer = properties.volume.layers[i];\n              let grainDirection = this.utils.initVector3(segment.layerProps.grainDirectionVector).normalize();\n\n              if (segment.type) {\n                let layerCount = Math.ceil(extrusionVector.z / layer.width);\n                let layerWidth = bboxDepth / layerCount;\n                let pointArr = segment.points;\n\n                for (let j = 0; j < layerCount; j++) {\n                  let rawGeo = this.GraphicsThree3D.makePositionedExtrusion({\n                    points2D: pointArr,\n                    depth: layerWidth,\n                    translation: [0, 0, j * layerWidth],\n                    skew: [0, 0]\n                  });\n                  let rawMesh = new this.THREE.Mesh(rawGeo);\n                  let modifiedMesh = BooleanOperations.doCSG(ellipseMesh, rawMesh, \"intersect\");\n                  let geometry = modifiedMesh.geometry;\n                  this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipseMesh.rotation]);\n                }\n              } else {\n                let horizontalSegments = this.segmentPointsHorizontal(segment.points, segment.layerProps);\n                horizontalSegments.forEach(pointArr => {\n                  let rawMesh = this.makeExtrudedMeshForCSG(pointArr, bboxDepth);\n                  let modifiedMesh = BooleanOperations.doCSG(ellipseMesh, rawMesh, \"intersect\");\n                  let geometry = modifiedMesh.geometry;\n                  this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipseMesh.rotation]);\n                });\n              }\n            }\n          }\n        } else if (ellipse.objectGeneration.type === 2) {\n          let centerPoint = this.utils.initVector3(ellipse.centerPoint);\n          let extrusionVector = this.utils.initVector3(ellipse.objectGeneration.extrusionVector);\n          let extrusionNormalized = this.utils.initVector3(extrusionVector).normalize();\n          let skewParams = this.utils.getSkewParams(extrusionVector);\n          let pts = this.GraphicsThree3D.getEllipsePlanarPoints(ellipse);\n          let [midVector, eulerOne, eulerTwo, crossVector] = this.GraphicsThree3D.getRotationParameters(pts, extrusionNormalized);\n          pts.forEach(point => {\n            point.sub(midVector);\n            point.applyEuler(eulerOne);\n          });\n          extrusionVector.applyEuler(eulerOne);\n\n          if (properties.volume.type === 2) {\n            let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n            let grainDirection = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n            let segments = this.segmentPointsVertical(pts, properties.volume);\n            segments.forEach(pointArr => {\n              let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n                points2D: pointArr,\n                depth: extrusionVector.z,\n                translation: [0, 0, 0],\n                skew: skewParams\n              });\n              this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, eulerTwo]);\n            });\n          } else if (properties.volume.type === 3) {\n            let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n            let grainDirectionOne = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n            let grainDirectionTwo = this.utils.initVector3(properties.volume.layers[1].grainDirectionVector).normalize();\n            let grainDirection;\n            let segments = this.segmentPointsVertical(pts, properties.volume);\n            segments.forEach(pointArr => {\n              grainDirection = pointArr.type ? grainDirectionOne : grainDirectionTwo;\n              let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n                points2D: pointArr.points,\n                depth: extrusionVector.z,\n                translation: [0, 0, 0],\n                skew: skewParams\n              });\n              this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, eulerTwo]);\n            });\n          } else if (properties.volume.type === 4) {\n            let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n            let segments = this.segmentPointsVertical(pts, properties.volume);\n\n            for (let i = 0; i < segments.length; i++) {\n              let segment = segments[i];\n              let layer = properties.volume.layers[i];\n              let grainDirection = this.utils.initVector3(segment.layerProps.grainDirectionVector).normalize();\n\n              if (segment.type) {\n                let layerCount = Math.ceil(extrusionVector.z / layer.width);\n                let layerWidth = extrusionVector.z / layerCount;\n                let pointArr = segment.points;\n\n                for (let j = 0; j < layerCount; j++) {\n                  let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n                    points2D: pointArr,\n                    depth: layerWidth,\n                    translation: [0, 0, j * layerWidth],\n                    skew: skewParams\n                  });\n                  this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, eulerTwo]);\n                }\n              } else {\n                let horizontalSegments = this.segmentPointsHorizontal(segment.points, segment.layerProps);\n                horizontalSegments.forEach(pointArr => {\n                  let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n                    points2D: pointArr,\n                    depth: extrusionVector.z,\n                    translation: [0, 0, 0],\n                    skew: skewParams\n                  });\n                  this.addToComplexVolumeData(ellipse, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, eulerTwo]);\n                });\n              }\n            }\n          }\n        }\n      });\n      return wireframes;\n    }\n\n    drawMultilayeredPolygons(polygons, properties, multilayeredObjects) {\n      let wireframes = [];\n      polygons.forEach(polygon => {\n        let extrusionVector = this.utils.initVector3(polygon.objectGeneration.extrusionVector);\n        let extrusionNormalized = this.utils.initVector3(extrusionVector).normalize();\n        let skewParams = this.utils.getSkewParams(extrusionVector);\n        let pts = this.GraphicsThree3D.DrawingObjectLoader.Polygon.getPolygonPlanarPoints(polygon);\n        let [midVector, eulerOne, eulerTwo, crossVector] = this.GraphicsThree3D.getRotationParameters(pts, extrusionNormalized);\n        pts.forEach(point => {\n          point.sub(midVector);\n          point.applyEuler(eulerOne);\n        });\n        extrusionVector.applyEuler(eulerOne);\n\n        if (properties.volume.type === 2) {\n          let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n          let grainDirection = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n          let segments = this.segmentPointsVertical(pts, properties.volume);\n          let polygonDepth = extrusionVector.z;\n          let translateZ = crossVector.dot(new this.THREE.Vector3(0, 0, -1)) > 0 ? -polygonDepth : 0;\n          segments.forEach(pointArr => {\n            let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n              points2D: pointArr,\n              depth: polygonDepth,\n              translation: [0, 0, translateZ],\n              skew: skewParams\n            });\n            this.addToComplexVolumeData(polygon, multilayeredObjects, [geometry, faceSideNormal, grainDirection, midVector, eulerTwo]);\n          });\n        } else if (properties.volume.type === 3) {\n          let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n          let grainDirectionOne = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n          let grainDirectionTwo = this.utils.initVector3(properties.volume.layers[1].grainDirectionVector).normalize();\n          let grainDirection;\n          let polygonDepth = extrusionVector.z;\n          let translateZ = crossVector.dot(new this.THREE.Vector3(0, 0, -1)) > 0 ? -polygonDepth : 0;\n          let segments = this.segmentPointsVertical(pts, properties.volume);\n          segments.forEach(pointArr => {\n            grainDirection = pointArr.type ? grainDirectionOne : grainDirectionTwo;\n            let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n              points2D: pointArr.points,\n              depth: polygonDepth,\n              translation: [0, 0, translateZ],\n              skew: skewParams\n            });\n            this.addToComplexVolumeData(polygon, multilayeredObjects, [geometry, faceSideNormal, grainDirection, midVector, eulerTwo]);\n          });\n        } else if (properties.volume.type === 4) {\n          let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n          let segments = this.segmentPointsVertical(pts, properties.volume);\n\n          for (let i = 0; i < segments.length; i++) {\n            let segment = segments[i];\n            let layer = properties.volume.layers[i];\n            let grainDirection = this.utils.initVector3(segment.layerProps.grainDirectionVector).normalize();\n\n            if (segment.type) {\n              let layerCount = Math.ceil(extrusionVector.z / layer.width);\n              let layerWidth = extrusionVector.z / layerCount;\n              let polygonDepth = layerWidth;\n              let translateZ = crossVector.dot(new this.THREE.Vector3(0, 0, -1)) > 0 ? -polygonDepth : polygonDepth;\n              let pointArr = segment.points;\n\n              for (let j = 0; j < layerCount; j++) {\n                let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n                  points2D: pointArr,\n                  depth: polygonDepth,\n                  translation: [0, 0, j * translateZ],\n                  skew: skewParams\n                });\n                this.addToComplexVolumeData(polygon, multilayeredObjects, [geometry, faceSideNormal, grainDirection, midVector, eulerTwo]);\n              }\n            } else {\n              let horizontalSegments = this.segmentPointsHorizontal(segment.points, segment.layerProps);\n              let polygonDepth = extrusionVector.z;\n              let translateZ = crossVector.dot(new this.THREE.Vector3(0, 0, -1)) > 0 ? -polygonDepth : 0;\n              horizontalSegments.forEach(pointArr => {\n                let geometry = this.GraphicsThree3D.makePositionedExtrusion({\n                  points2D: pointArr,\n                  depth: polygonDepth,\n                  translation: [0, 0, translateZ],\n                  skew: skewParams\n                });\n                this.addToComplexVolumeData(polygon, multilayeredObjects, [geometry, faceSideNormal, grainDirection, midVector, eulerTwo]);\n              });\n            }\n          }\n        }\n      });\n      return wireframes;\n    }\n\n    drawMultilayeredEllipsoids(ellipsoids, properties, multilayeredObjects) {\n      const SIZE_DELTA = 1;\n      let wireframes = [];\n      ellipsoids.forEach(ellipsoid => {\n        let ellipsoidMesh = this.GraphicsThree3D.DrawingObjectLoader.Ellipsoid.drawEllipsoid(ellipsoid);\n        ellipsoidMesh.geometry.computeBoundingBox();\n        let bbox = ellipsoidMesh.geometry.boundingBox;\n        let bboxDepth = bbox.max.z - bbox.min.z + SIZE_DELTA;\n        let pts = [new this.THREE.Vector3(bbox.min.x - SIZE_DELTA, bbox.min.y - SIZE_DELTA, 0), new this.THREE.Vector3(bbox.max.x + SIZE_DELTA, bbox.min.y - SIZE_DELTA, 0), new this.THREE.Vector3(bbox.max.x + SIZE_DELTA, bbox.max.y + SIZE_DELTA, 0), new this.THREE.Vector3(bbox.min.x - SIZE_DELTA, bbox.max.y + SIZE_DELTA, 0)];\n        let extrusionVector = new this.THREE.Vector3(0, 0, bboxDepth);\n        let centerPoint = this.utils.initVector3(ellipsoid.centerPoint);\n        ellipsoidMesh.position.sub(centerPoint).add(extrusionVector.clone().multiplyScalar(0.5));\n        ellipsoidMesh.updateMatrix();\n        centerPoint.add(extrusionVector.clone().multiplyScalar(0.5));\n\n        if (properties.volume.type === 2) {\n          let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n          let grainDirection = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n          let segments = this.segmentPointsVertical(pts, properties.volume);\n          segments.forEach(pointArr => {\n            let rawGeo = this.GraphicsThree3D.makePositionedExtrusion({\n              points2D: pointArr,\n              depth: bboxDepth,\n              translation: [0, 0, 0],\n              skew: [0, 0]\n            });\n            let rawMesh = new this.THREE.Mesh(rawGeo);\n            let modifiedMesh = BooleanOperations.doCSG(ellipsoidMesh, rawMesh, \"intersect\");\n            let geometry = modifiedMesh.geometry;\n            this.addToComplexVolumeData(ellipsoid, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipsoidMesh.rotation]);\n          });\n        } else if (properties.volume.type === 3) {\n          let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n          let grainDirectionOne = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n          let grainDirectionTwo = this.utils.initVector3(properties.volume.layers[1].grainDirectionVector).normalize();\n          let grainDirection;\n          let segments = this.segmentPointsVertical(pts, properties.volume);\n          segments.forEach(pointArr => {\n            grainDirection = pointArr.type ? grainDirectionOne : grainDirectionTwo;\n            let rawGeo = this.GraphicsThree3D.makePositionedExtrusion({\n              points2D: pointArr.points,\n              depth: bboxDepth,\n              translation: [0, 0, 0],\n              skew: [0, 0]\n            });\n            let rawMesh = new this.THREE.Mesh(rawGeo);\n            let modifiedMesh = BooleanOperations.doCSG(ellipsoidMesh, rawMesh, \"intersect\");\n            let geometry = modifiedMesh.geometry;\n            this.addToComplexVolumeData(ellipsoid, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipsoidMesh.rotation]);\n          });\n        } else if (properties.volume.type === 4) {\n          let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n          let segments = this.segmentPointsVertical(pts, properties.volume);\n\n          for (let i = 0; i < segments.length; i++) {\n            let segment = segments[i];\n            let layer = properties.volume.layers[i];\n            let grainDirection = this.utils.initVector3(segment.layerProps.grainDirectionVector).normalize();\n\n            if (segment.type) {\n              let layerCount = Math.ceil(extrusionVector.z / layer.width);\n              let layerWidth = bboxDepth / layerCount;\n              let pointArr = segment.points;\n\n              for (let j = 0; j < layerCount; j++) {\n                let rawGeo = this.GraphicsThree3D.makePositionedExtrusion({\n                  points2D: pointArr,\n                  depth: layerWidth,\n                  translation: [0, 0, j * layerWidth],\n                  skew: [0, 0]\n                });\n                let rawMesh = new this.THREE.Mesh(rawGeo);\n                let modifiedMesh = BooleanOperations.doCSG(ellipsoidMesh, rawMesh, \"intersect\");\n                let geometry = modifiedMesh.geometry;\n                this.addToComplexVolumeData(ellipsoid, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipsoidMesh.rotation]);\n              }\n            } else {\n              let horizontalSegments = this.segmentPointsHorizontal(segment.points, segment.layerProps);\n              horizontalSegments.forEach(pointArr => {\n                let rawGeo = this.GraphicsThree3D.makePositionedExtrusion({\n                  points2D: pointArr,\n                  depth: bboxDepth,\n                  translation: [0, 0, 0],\n                  skew: [0, 0]\n                });\n                let rawMesh = new this.THREE.Mesh(rawGeo);\n                let modifiedMesh = BooleanOperations.doCSG(ellipsoidMesh, rawMesh, \"intersect\");\n                let geometry = modifiedMesh.geometry;\n                this.addToComplexVolumeData(ellipsoid, multilayeredObjects, [geometry, faceSideNormal, grainDirection, centerPoint, ellipsoidMesh.rotation]);\n              });\n            }\n          }\n        }\n      });\n      return wireframes;\n    }\n\n    addToComplexVolumeData(objectData, multilayeredObjects, [geometry, faceSideNormal, grainDirection, midVector, eulerTwo]) {\n      if (objectData.objectType === 1) multilayeredObjects.positives.push([geometry, faceSideNormal, grainDirection, midVector, eulerTwo]);else multilayeredObjects.negatives.push([geometry, faceSideNormal, grainDirection, midVector, eulerTwo]);\n    }\n\n    segmentPointsVertical(points, volumeProps) {\n      let PolyBool = this.GraphicsThree3D.PolyBool;\n      let ptsPolygon = {\n        regions: [[]],\n        inverted: false\n      };\n      let maxX = 0,\n          maxY = 0;\n      let minX = Infinity,\n          minY = Infinity;\n      points.forEach(point => {\n        if (point.x > maxX) maxX = point.x;\n        if (point.y > maxY) maxY = point.y;\n        if (point.x < minX) minX = point.x;\n        if (point.y < minY) minY = point.y;\n        ptsPolygon.regions[0].push([point.x, point.y]);\n      });\n      let segments = [];\n\n      if (volumeProps.type == 2) {\n        let layerThickness = volumeProps.layers[0].thickness;\n        let eraserPolygon = {\n          regions: [],\n          inverted: false\n        };\n\n        while (minY < maxY) {\n          let eraserRegion = [];\n          eraserRegion.push([minX, minY]);\n          eraserRegion.push([maxX, minY]);\n          eraserRegion.push([maxX, minY + layerThickness]);\n          eraserRegion.push([minX, minY + layerThickness]);\n          eraserPolygon.regions.push(eraserRegion);\n          minY += 2 * layerThickness;\n        }\n\n        let polygonOne = PolyBool.difference(ptsPolygon, eraserPolygon);\n        let polygonTwo = PolyBool.intersect(ptsPolygon, eraserPolygon);\n        polygonOne.regions.forEach(region => {\n          let pointArr = [];\n          region.forEach(point => pointArr.push(new this.THREE.Vector2(point[0], point[1])));\n          segments.push(pointArr);\n        });\n        polygonTwo.regions.forEach(region => {\n          let pointArr = [];\n          region.forEach(point => pointArr.push(new this.THREE.Vector2(point[0], point[1])));\n          segments.push(pointArr);\n        });\n      } else if (volumeProps.type == 3) {\n        let objectHeight = maxY - minY;\n        let layerThickness = objectHeight / Math.ceil(objectHeight / volumeProps.layers[0].thickness);\n        let eraserPolygon = {\n          regions: [],\n          inverted: false\n        };\n\n        while (minY < maxY) {\n          let eraserRegion = [];\n          eraserRegion.push([minX, minY]);\n          eraserRegion.push([maxX, minY]);\n          eraserRegion.push([maxX, minY + layerThickness]);\n          eraserRegion.push([minX, minY + layerThickness]);\n          eraserPolygon.regions.push(eraserRegion);\n          minY += 2 * layerThickness;\n        }\n\n        let polygonOne = PolyBool.difference(ptsPolygon, eraserPolygon);\n        let polygonTwo = PolyBool.intersect(ptsPolygon, eraserPolygon);\n        polygonOne.regions.forEach(region => {\n          let pointArr = {\n            points: [],\n            type: 0\n          };\n          region.forEach(point => pointArr.points.push(new this.THREE.Vector2(point[0], point[1])));\n          segments.push(pointArr);\n        });\n        polygonTwo.regions.forEach(region => {\n          let pointArr = {\n            points: [],\n            type: 1\n          };\n          region.forEach(point => pointArr.points.push(new this.THREE.Vector2(point[0], point[1])));\n          segments.push(pointArr);\n        });\n      } else {\n        let layers = volumeProps.layers;\n        let eraserPolygon = {\n          regions: [],\n          inverted: false\n        };\n        let layersHeight = layers.map(layer => layer = layer.thickness).reduce((a, b) => a + b, 0);\n        let objectHeight = maxY - minY;\n\n        if (layersHeight != objectHeight) {\n          let proportion = objectHeight / layersHeight;\n          layers.forEach(layer => layer.thickness *= proportion);\n        }\n\n        let layerPropsEven = [];\n        let layerPropsOdd = [];\n\n        for (let i = 0; i < layers.length; i++) {\n          let layerThickness = layers[i].thickness;\n\n          if (i % 2 == 0) {\n            let eraserRegion = [];\n            eraserRegion.push([minX, minY]);\n            eraserRegion.push([maxX, minY]);\n            eraserRegion.push([maxX, minY + layerThickness]);\n            eraserRegion.push([minX, minY + layerThickness]);\n            eraserPolygon.regions.push(eraserRegion);\n            layerPropsEven.push(layers[i]);\n          } else {\n            layerPropsOdd.push(layers[i]);\n          }\n\n          minY += layerThickness;\n        }\n\n        let polygonOne = PolyBool.difference(ptsPolygon, eraserPolygon);\n        let polygonTwo = PolyBool.intersect(ptsPolygon, eraserPolygon);\n        polygonOne.regions.forEach((region, index) => {\n          let pointArr = {\n            points: [],\n            type: 0,\n            layerProps: layerPropsOdd[index]\n          };\n          region.forEach(point => pointArr.points.push(new this.THREE.Vector2(point[0], point[1])));\n          segments.push(pointArr);\n        });\n        polygonTwo.regions.forEach((region, index) => {\n          let pointArr = {\n            points: [],\n            type: 1,\n            layerProps: layerPropsEven[index]\n          };\n          region.forEach(point => pointArr.points.push(new this.THREE.Vector2(point[0], point[1])));\n          segments.push(pointArr);\n        });\n      }\n\n      return segments;\n    }\n\n    segmentPointsHorizontal(points, layerProps) {\n      let PolyBool = this.GraphicsThree3D.PolyBool;\n      let segments = [];\n      let ptsPolygon = {\n        regions: [[]],\n        inverted: false\n      };\n      let maxX = 0,\n          maxY = 0;\n      let minX = Infinity,\n          minY = Infinity;\n      points.forEach(point => {\n        if (point.x > maxX) maxX = point.x;\n        if (point.y > maxY) maxY = point.y;\n        if (point.x < minX) minX = point.x;\n        if (point.y < minY) minY = point.y;\n        ptsPolygon.regions[0].push([point.x, point.y]);\n      });\n      let eraserPolygon = {\n        regions: [],\n        inverted: false\n      };\n      let objectWidth = maxX - minX;\n      let segmentWidth = layerProps.width;\n      let segmentCount = Math.ceil(objectWidth / segmentWidth);\n      segmentWidth = objectWidth / segmentCount;\n\n      while (minX < maxX) {\n        let eraserRegion = [];\n        eraserRegion.push([minX, maxY]);\n        eraserRegion.push([minX, minY]);\n        eraserRegion.push([minX + segmentWidth, minY]);\n        eraserRegion.push([minX + segmentWidth, maxY]);\n        eraserPolygon.regions.push(eraserRegion);\n        minX += 2 * segmentWidth;\n      }\n\n      let polygonOne = PolyBool.difference(ptsPolygon, eraserPolygon);\n      let polygonTwo = PolyBool.intersect(ptsPolygon, eraserPolygon);\n      polygonOne.regions.forEach(region => {\n        let pointArr = [];\n        region.forEach(point => pointArr.push(new this.THREE.Vector2(point[0], point[1])));\n        segments.push(pointArr);\n      });\n      polygonTwo.regions.forEach(region => {\n        let pointArr = [];\n        region.forEach(point => pointArr.push(new this.THREE.Vector2(point[0], point[1])));\n        segments.push(pointArr);\n      });\n      return segments;\n    }\n\n  }\n\n  _exports.ComplexVolume = ComplexVolume;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Ellipse\", [\"exports\", \"m08-2020/lib/ThreeExtensions/RotatedGeometry\", \"m08-2020/lib/ThreeExtensions/PlanarRotationPointsGenerator\", \"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Ellipsoid\"], function (_exports, _RotatedGeometry, _PlanarRotationPointsGenerator, _Ellipsoid) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.Ellipse = void 0;\n\n  class Ellipse {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.THREE = GraphicsThree3D.THREE;\n      this.utils = GraphicsThree3D.utils;\n      this.CSG = GraphicsThree3D.CSG;\n      this.WireframeGenerator = GraphicsThree3D.WireframeGenerator;\n      this.Ellipsoid = new _Ellipsoid.Ellipsoid(GraphicsThree3D);\n    }\n\n    drawEllipse(ellipseData) {\n      let ellipseType = ellipseData.objectGeneration.type;\n      let ellipseMesh;\n\n      if (ellipseType === 1 || ellipseType === 3 && !ellipseData.objectGeneration.rotationAngle) {\n        ellipseMesh = this.drawEllipsePlanar(ellipseData);\n        ellipseMesh.generationType = \"area\";\n      } else if (ellipseType === 2) {\n        if (this.GraphicsThree3D.objectExtrudesPlanar(ellipseData, true)) {\n          ellipseMesh = this.makeEllipseExtrudedArea(ellipseData);\n          ellipseMesh.generationType = \"area\";\n        } else {\n          ellipseMesh = this.makeEllipseExtrudedVolume(ellipseData);\n          ellipseMesh.generationType = \"volume\";\n        }\n      } else if (ellipseType === 3) {\n        if (this.GraphicsThree3D.objectRotatesPlanar(ellipseData, true)) {\n          ellipseMesh = this.makeEllipseRotatedArea(ellipseData);\n          ellipseMesh.generationType = \"area\";\n        } else {\n          ellipseMesh = this.makeEllipseRotatedVolume(ellipseData);\n          ellipseMesh.generationType = \"volume\";\n        }\n      }\n\n      return ellipseMesh;\n    }\n\n    drawEllipsePlanar(ellipseData) {\n      let centerPoint = this.utils.initVector3(ellipseData.centerPoint);\n      let extrusionDepth = 0.1;\n      let extrusionVector = new this.THREE.Vector3(0, 0, extrusionDepth);\n      let extrusionNormalized = extrusionVector.clone().normalize();\n      let pts = this.GraphicsThree3D.getEllipsePlanarPoints(ellipseData);\n      let [midVector, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(pts, extrusionNormalized);\n      pts.forEach(point => {\n        // this.GraphicsThree3D.wireframePoints.push(point.clone().add(centerPoint));\n        point.sub(midVector);\n        point.applyEuler(eulerOne);\n      });\n      let shapePts = pts.map(point => new this.THREE.Vector2(point.x, point.y));\n      let ellipseShape = new this.THREE.Shape(shapePts);\n      extrusionVector.applyEuler(eulerOne);\n      extrusionNormalized.applyEuler(eulerOne);\n      let extrudeSettings = {\n        depth: extrusionDepth,\n        bevelEnabled: false\n      };\n      let ellipseGeo = new this.THREE.ExtrudeGeometry(ellipseShape, extrudeSettings); // ellipseGeo.translate(0, 0, -extrusionVector.z);\n\n      let ellipse = new this.THREE.Mesh(ellipseGeo);\n      ellipse.position.add(midVector);\n      ellipse.updateMatrix();\n      ellipse.setRotationFromEuler(eulerTwo);\n      ellipse.position.add(centerPoint);\n      return ellipse;\n    }\n\n    makeEllipseExtrudedArea(ellipseData) {\n      let centerPoint = this.utils.initVector3(ellipseData.centerPoint);\n      let extrusionVector = new this.THREE.Vector3(ellipseData.objectGeneration.extrusionVector.x, ellipseData.objectGeneration.extrusionVector.y, 0);\n      let curvePoints = this.GraphicsThree3D.getEllipsePlanarPoints(ellipseData); // TODO: Refactor this to be more readable end efficient\n\n      if (ellipseData.segmentVector1) {\n        if (!ellipseData.segmentHeight) {\n          curvePoints.splice(2, 0, curvePoints[1].clone());\n          curvePoints.splice(curvePoints.length - 1, 0, curvePoints[curvePoints.length - 1].clone());\n\n          for (let i = 2; i < curvePoints.length - 1; i++) {\n            curvePoints[i].add(extrusionVector);\n          }\n        } else {\n          let extrusionDir = extrusionVector.clone().normalize();\n          let midDir = curvePoints[Math.floor(curvePoints.length / 2)].clone().normalize(); ///\n\n          if (midDir.dot(extrusionDir) < 0) {\n            curvePoints.splice(2, 0, curvePoints[1].clone());\n            curvePoints.splice(curvePoints.length - 1, 0, curvePoints[curvePoints.length - 2].clone());\n\n            for (let i = 0; i < 2; i++) {\n              curvePoints[i].add(extrusionVector);\n            }\n\n            for (let i = curvePoints.length - 2; i < curvePoints.length; i++) {\n              curvePoints[i].add(extrusionVector);\n            }\n          } else {\n            curvePoints.splice(2, 0, curvePoints[1].clone());\n            curvePoints.splice(curvePoints.length - 1, 0, curvePoints[curvePoints.length - 2].clone());\n\n            for (let i = 2; i < curvePoints.length - 2; i++) {\n              curvePoints[i].add(extrusionVector);\n            }\n          }\n        }\n      } else {\n        curvePoints.push(curvePoints[0].clone());\n        let pointsNum = curvePoints.length;\n        let startIndex = (Math.PI / 2 + extrusionVector.angleTo(new this.THREE.Vector3(1, 0, 0))) / (2 * Math.PI) * pointsNum;\n        let endIndex = (3 * Math.PI / 2 + extrusionVector.angleTo(new this.THREE.Vector3(1, 0, 0))) / (2 * Math.PI) * pointsNum;\n\n        if (endIndex >= pointsNum) {\n          endIndex -= pointsNum;\n        }\n\n        startIndex = Math.floor(startIndex);\n        endIndex = Math.floor(endIndex);\n\n        if (startIndex < endIndex) {\n          for (let i = 0; i < startIndex; i++) {\n            curvePoints[i].add(extrusionVector);\n          }\n\n          for (let i = endIndex; i < pointsNum; i++) {\n            curvePoints[i].add(extrusionVector);\n          }\n        } else {\n          for (let i = endIndex; i < startIndex; i++) {\n            curvePoints[i].add(extrusionVector);\n          }\n        }\n      }\n\n      let curveShape = new this.THREE.Shape(curvePoints);\n      let curveGeo = new this.THREE.ExtrudeBufferGeometry(curveShape, {\n        depth: -0.01,\n        bevelEnabled: false\n      });\n      let ellipse = new this.THREE.Mesh(curveGeo);\n      ellipse.position.add(centerPoint);\n      return ellipse;\n    }\n\n    makeEllipseExtrudedVolume(ellipseData) {\n      let centerPoint = this.utils.initVector3(ellipseData.centerPoint);\n      let extrusionVector = ellipseData.objectGeneration.extrusionVector;\n      let extrusionNormalized = this.utils.initVector3(extrusionVector).normalize();\n      let skewX = extrusionNormalized.x / extrusionNormalized.z;\n      let skewY = extrusionNormalized.y / extrusionNormalized.z;\n      let curvePoints = this.GraphicsThree3D.getEllipsePlanarPoints(ellipseData); // this.WireframeGenerator.getPlanarPoints(curvePoints.map(point => point.clone().add(centerPoint)), ellipseData.objectType);\n\n      let curveShape = new this.THREE.Shape(curvePoints);\n      let curveGeo = new this.THREE.ExtrudeGeometry(curveShape, {\n        depth: extrusionVector.z,\n        bevelEnabled: false\n      }); // curveGeo.translate(0, 0, extrusionVector.z);\n\n      curveGeo.applyMatrix4(new this.THREE.Matrix4().set(1, 0, skewX, 0, 0, 1, skewY, 0, 0, 0, 1, 0, 0, 0, 0, 1));\n      let ellipse = new this.THREE.Mesh(curveGeo);\n      ellipse.position.copy(centerPoint);\n      ellipse.updateMatrix(); ///\n\n      let linePairs = [];\n      this.WireframeGenerator.getRegularWireframePointPairs(ellipse, Math.PI / 720).forEach(pair => linePairs.push([pair[0].clone().applyMatrix4(ellipse.matrix), pair[1].clone().applyMatrix4(ellipse.matrix)]));\n      let linePairsForOpaque = [];\n      this.WireframeGenerator.getRegularWireframePointPairs(ellipse, 20 * Math.PI / 180).forEach(pair => linePairsForOpaque.push([pair[0].clone().applyMatrix4(ellipse.matrix), pair[1].clone().applyMatrix4(ellipse.matrix)]));\n      this.WireframeGenerator.getVolumeWireframeData(ellipse, linePairsForOpaque, linePairs, ellipseData.objectType); ///\n\n      return ellipse;\n    }\n\n    makeEllipseRotatedArea(ellipseData) {\n      const DELTA = 0.0001;\n      let centerPoint = ellipseData.centerPoint;\n      let rotationPoint = ellipseData.objectGeneration.rotationPoint;\n      let rotationAngle = ellipseData.objectGeneration.rotationAngle * Math.PI / 180;\n      let rotationPitch = ellipseData.objectGeneration.rotationPitch;\n      let rotationAxis = this.utils.initVector3(ellipseData.objectGeneration.rotationAxis);\n      let centerVector = this.utils.initVector3(centerPoint);\n      let rotationVector = this.utils.initVector3(rotationPoint).sub(centerVector);\n      let curvePoints = this.GraphicsThree3D.getEllipsePlanarPoints(ellipseData).map(point => point.sub(rotationVector));\n      let zAxis = new this.THREE.Vector3(0, 0, 1);\n      let [_, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(curvePoints, zAxis);\n      if (curvePoints[0].distanceTo(curvePoints[curvePoints.length - 1]) < DELTA) curvePoints.pop();\n      curvePoints.forEach(point => point.applyEuler(eulerOne));\n      if (rotationAxis.applyEuler(eulerOne).dot(zAxis) < 0) rotationAngle *= -1;\n      curvePoints = new _PlanarRotationPointsGenerator.PlanarRotationPointsGenerator(curvePoints, {\n        rotationAngle,\n        rotationPitch\n      }).rotatedPoints;\n      let ellipse = this.drawExtrudedEllipseMesh(curvePoints, -0.01);\n      ellipse.setRotationFromEuler(eulerTwo);\n      ellipse.position.set(rotationPoint.x, rotationPoint.y, rotationPoint.z);\n      return ellipse;\n    }\n\n    drawExtrudedEllipseMesh(shapePts, extrDepth) {\n      let curveShape = new this.THREE.Shape(shapePts);\n      let curveGeo = new this.THREE.ExtrudeGeometry(curveShape, {\n        depth: extrDepth,\n        bevelEnabled: false\n      });\n      return new this.THREE.Mesh(curveGeo);\n    }\n\n    makeEllipseRotatedVolume(ellipseData) {\n      let ellipse;\n\n      if (this.rotationAxisDefined(ellipseData.objectGeneration.rotationAxis)) {\n        let centerPoint = this.utils.initVector3(ellipseData.centerPoint);\n        let rotationPoint = this.utils.initVector3(ellipseData.objectGeneration.rotationPoint);\n        let rotationAxis = this.utils.initVector3(ellipseData.objectGeneration.rotationAxis).normalize();\n        let rotationAngle = ellipseData.objectGeneration.rotationAngle * Math.PI / 180;\n        let rotationPitch = ellipseData.objectGeneration.rotationPitch;\n        let rotationRadius = centerPoint.distanceTo(rotationPoint);\n\n        if (this.generatesEllipsoid(rotationRadius, rotationAngle, rotationPitch)) {\n          let ellipsoidData = this.generateEllipsoidData(ellipseData, rotationAxis);\n          ellipse = this.Ellipsoid.drawEllipsoid(ellipsoidData);\n        } else {\n          let pts = this.GraphicsThree3D.getEllipsePlanarPoints(ellipseData).map(pt => pt.add(centerPoint));\n          let rotationParams = {\n            rotationPoint: this.utils.initVector3(ellipseData.objectGeneration.rotationPoint),\n            rotationAxis: this.utils.initVector3(ellipseData.objectGeneration.rotationAxis).normalize(),\n            rotationAngle: ellipseData.objectGeneration.rotationAngle * Math.PI / 180,\n            rotationPitch: ellipseData.objectGeneration.rotationPitch\n          };\n          let rotatedGeometry = new _RotatedGeometry.RotatedGeometry(pts.map(pt => pt.clone()), rotationParams);\n          ellipse = new this.THREE.Mesh(rotatedGeometry);\n          ellipse.updateMatrix();\n          this.addToWireframePts3D(ellipse, ellipseData, pts, rotationParams);\n        }\n      } else ellipse = new this.THREE.Mesh();\n\n      return ellipse;\n    }\n\n    addToWireframePts3D(ellipseMesh, ellipseData, ellipsePts, rotationParams) {\n      let {\n        rotationPoint,\n        rotationAxis,\n        rotationAngle,\n        rotationPitch\n      } = rotationParams;\n      let wireframePts = [...ellipsePts, ellipsePts[0]];\n      let linePairs = this.WireframeGenerator.getRegularWireframePointPairs(ellipseMesh, Math.PI / 180).map(pair => [pair[0].clone().applyMatrix4(ellipseMesh.matrix), pair[1].clone().applyMatrix4(ellipseMesh.matrix)]);\n      let linePairsForOpaque = [];\n      let pitchVec = rotationAxis.clone().multiplyScalar(rotationPitch * Math.abs(rotationAngle) / (2 * Math.PI));\n\n      for (let i = 0, l = wireframePts.length - 1; i < l; i++) {\n        linePairsForOpaque.push([wireframePts[i], wireframePts[i + 1]]);\n        let rotatedPoints = [wireframePts[i], wireframePts[i + 1]].map(pt => pt.clone().sub(rotationPoint).applyAxisAngle(rotationAxis, rotationAngle).add(rotationPoint).add(pitchVec));\n        linePairsForOpaque.push(rotatedPoints);\n      }\n\n      if (ellipseData.segmentVector1 && ellipseData.segmentVector2) {\n        let ptsToRotate = [];\n        ptsToRotate.push(ellipsePts[ellipsePts.length - 1], ellipsePts[ellipsePts.length - 2]);\n        ptsToRotate.push(ellipsePts[0]);\n        if (ellipseData.segmentHeight) ptsToRotate.push(ellipsePts[1]);\n        const DETAIL = 64;\n        let numOfSegments = DETAIL * Math.abs(rotationAngle) / (2 * Math.PI);\n        let pitchVector = new this.THREE.Vector3();\n\n        for (let point of ptsToRotate) {\n          let sidePoints = [];\n\n          for (let i = 0; i < numOfSegments; i++) {\n            let rotatedPoint = new this.THREE.Vector3().copy(point).sub(rotationPoint).applyAxisAngle(rotationAxis, (i + 1) * rotationAngle / numOfSegments).add(rotationPoint).add(pitchVector.copy(rotationAxis).multiplyScalar((i + 1) * rotationPitch / numOfSegments / 2));\n            sidePoints.push(rotatedPoint);\n          }\n\n          linePairsForOpaque.push([point, sidePoints[0]]);\n\n          for (let j = 0; j < sidePoints.length - 1; j++) linePairsForOpaque.push([sidePoints[j], sidePoints[j + 1]]);\n        }\n      }\n\n      this.WireframeGenerator.getVolumeWireframeData(ellipseMesh, linePairsForOpaque, linePairs, ellipseData.objectType);\n    }\n\n    rotationAxisDefined(rotationAxis) {\n      return rotationAxis && (rotationAxis.x || rotationAxis.y || rotationAxis.z);\n    }\n\n    generatesEllipsoid(rotationRadius, rotationAngle, rotationPitch) {\n      return rotationRadius <= 0.01 && !rotationPitch && rotationAngle >= Math.PI;\n    }\n\n    getProjectedVectorLengthSquared(initialVec, targetVec, targetLen) {\n      let projectedVectorLengthSquared = initialVec.clone().projectOnVector(targetVec).multiplyScalar(targetLen).lengthSq();\n      return projectedVectorLengthSquared;\n    }\n\n    generateEllipsoidData(ellipseData, rotationAxis) {\n      let dir1 = this.utils.initVector3(ellipseData.directionVector1),\n          dir2 = this.utils.initVector3(ellipseData.directionVector2);\n      let dir3 = new this.THREE.Vector3().crossVectors(dir1, dir2).normalize();\n      let projOneLenSq = this.getProjectedVectorLengthSquared(rotationAxis, dir1, ellipseData.radius1);\n      let projTwoLenSq = this.getProjectedVectorLengthSquared(rotationAxis, dir2, ellipseData.radius2);\n      let radius3 = Math.sqrt(projOneLenSq + projTwoLenSq);\n      let ellipsoidData = { ...ellipseData,\n        radius3,\n        directionVector3: dir3\n      };\n      return ellipsoidData;\n    }\n\n  }\n\n  _exports.Ellipse = Ellipse;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Ellipsoid\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.Ellipsoid = void 0;\n\n  class Ellipsoid {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.THREE = GraphicsThree3D.THREE;\n      this.utils = GraphicsThree3D.utils;\n      this.CSG = GraphicsThree3D.CSG;\n      this.WireframeGenerator = GraphicsThree3D.WireframeGenerator;\n    }\n\n    drawEllipsoid(ellipsoidData) {\n      console.log(ellipsoidData);\n      let centerPoint = this.utils.initVector3(ellipsoidData.centerPoint);\n      let directionVectorOne = this.utils.initVector3(ellipsoidData.directionVector1).normalize();\n      let directionVectorTwo = this.utils.initVector3(ellipsoidData.directionVector2).normalize();\n      let directionVectorThree = this.utils.initVector3(ellipsoidData.directionVector3).normalize();\n      let radiusOne = ellipsoidData.radius1;\n      let radiusTwo = ellipsoidData.radius2;\n      let radiusThree = ellipsoidData.radius3;\n      let segmentHeight = ellipsoidData.segmentHeight;\n      let ellipsoidMesh = this.makeEllipsoidMesh(radiusOne, radiusTwo, radiusThree);\n\n      if (this.segmentVectorsAreValid(ellipsoidData.segmentVector1, ellipsoidData.segmentVector2)) {\n        let segmentVectorOne = this.utils.initVector3(ellipsoidData.segmentVector1).normalize();\n        let segmentVectorTwo = this.utils.initVector3(ellipsoidData.segmentVector2).normalize();\n        let segmentsCross = this.utils.getCrossVector(segmentVectorOne, segmentVectorTwo);\n        let directionsCross = this.utils.getCrossVector(directionVectorOne, directionVectorTwo);\n        let segmentsCrossLength = segmentsCross.length();\n        let crossVector = segmentsCrossLength !== 0 ? segmentsCross : directionsCross;\n        let isOnPlane = false;\n\n        for (let vector of [directionVectorOne, directionVectorTwo, directionVectorThree]) {\n          if (Math.abs(vector.dot(crossVector)) === 1) isOnPlane = true;\n          if (vector.dot(crossVector) === -1) crossVector.negate();\n        }\n\n        if (isOnPlane) {\n          let segmentQuaternion = new this.THREE.Quaternion().setFromUnitVectors(crossVector, new this.THREE.Vector3(0, 0, 1));\n          segmentVectorOne.applyQuaternion(segmentQuaternion);\n          segmentVectorTwo.applyQuaternion(segmentQuaternion);\n          let maxRadius = Math.max(radiusOne, radiusTwo, radiusThree) + 1;\n          let boxSize = 2 * maxRadius;\n          let pointsData = {\n            centerPoint: {\n              x: ellipsoidData.centerPoint.x,\n              y: ellipsoidData.centerPoint.y,\n              z: ellipsoidData.centerPoint.z\n            },\n            directionVector1: {\n              x: ellipsoidData.directionVector1.x,\n              y: ellipsoidData.directionVector1.y,\n              z: ellipsoidData.directionVector1.z\n            },\n            directionVector2: {\n              x: ellipsoidData.directionVector2.x,\n              y: ellipsoidData.directionVector2.y,\n              z: ellipsoidData.directionVector2.z\n            },\n            radius1: maxRadius,\n            radius2: maxRadius,\n            segmentHeight: 0,\n            segmentVector1: {\n              x: segmentVectorOne.x,\n              y: segmentVectorOne.y,\n              z: segmentVectorOne.z\n            },\n            segmentVector2: {\n              x: segmentVectorTwo.x,\n              y: segmentVectorTwo.y,\n              z: segmentVectorTwo.z\n            }\n          };\n          let pts = this.GraphicsThree3D.getEllipsePlanarPoints(pointsData);\n          if (segmentsCrossLength === 0) pts.pop();\n          let [midVector, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(pts, new this.THREE.Vector3(0, 0, 1));\n          pts.forEach(point => {\n            point.sub(midVector);\n            point.applyEuler(eulerOne);\n            point.add(midVector);\n          });\n          let eraserPoints = pts.map(point => new this.THREE.Vector2(point.x, point.y));\n          let eraserShape = new this.THREE.Shape(eraserPoints);\n          let eraserGeometry = new this.THREE.ExtrudeGeometry(eraserShape, {\n            steps: 1,\n            bevelEnabled: false,\n            depth: boxSize\n          });\n          eraserGeometry.translate(0, 0, -boxSize / 2);\n          let eraserMesh = new this.THREE.Mesh(eraserGeometry);\n          eraserMesh.lookAt(crossVector);\n          eraserMesh.updateMatrix();\n          let ellipsoidCSG = this.CSG.fromMesh(ellipsoidMesh);\n          let eraserCSG = this.CSG.fromMesh(eraserMesh);\n          ellipsoidCSG = ellipsoidCSG.intersect(eraserCSG);\n\n          if (segmentHeight) {\n            let [segOne, segTwo] = this.getEllipsoidSegments(ellipsoidCSG, segmentVectorOne, segmentVectorTwo);\n            let midVector = segmentsCrossLength !== 0 ? new this.THREE.Vector3().lerpVectors(segOne, segTwo, 0.5).normalize() : new this.THREE.Vector3().crossVectors(segmentVectorOne, crossVector);\n            let maxDistance = 0,\n                midPoint = new this.THREE.Vector3();\n            ellipsoidCSG.polygons.forEach(polygon => polygon.vertices.forEach(vertex => {\n              let localVertex = new this.THREE.Vector3(vertex.pos.x, vertex.pos.y, vertex.pos.z);\n              let dir = localVertex.clone().normalize().dot(midVector);\n              let distance = midVector.clone().dot(localVertex);\n\n              if (dir > 0.99) {\n                if (distance > maxDistance) {\n                  maxDistance = distance;\n                  midPoint.copy(localVertex);\n                }\n              } else if (dir < -0.99) {\n                if (-distance > maxDistance) {\n                  maxDistance = -distance;\n                  midPoint.copy(localVertex.clone().negate());\n                }\n              }\n            }));\n            let midRadius = midPoint.length();\n\n            if (segmentsCrossLength === 0) {\n              let heightDelta = midRadius - segmentHeight;\n              let eraserBox = new this.THREE.Mesh(new this.THREE.BoxGeometry(boxSize, boxSize, boxSize));\n              eraserBox.lookAt(midVector.clone().normalize());\n              eraserBox.position.add(new this.THREE.Vector3().copy(midVector).normalize().multiplyScalar(boxSize / 2 - heightDelta));\n              eraserBox.updateMatrix();\n              let heightEraserCSG = this.CSG.fromMesh(eraserBox);\n              ellipsoidCSG = ellipsoidCSG.subtract(heightEraserCSG);\n            } else {\n              if (pts.length > 32) {\n                let maxHeight = midRadius + new this.THREE.Vector3().lerpVectors(segOne, segTwo, 0.5).length();\n\n                if (segmentHeight <= maxHeight) {\n                  if (segmentHeight > midRadius) {\n                    let heightDelta = segmentHeight - midRadius;\n                    let dir = segOne.clone().sub(segTwo).normalize();\n                    let eraserBox = new this.THREE.Mesh(new this.THREE.BoxGeometry(boxSize, boxSize, boxSize));\n                    let upVector = this.getMeshUpVector(eraserBox, dir);\n                    let delta = this.getDifferenceUpAndMid(upVector, new this.THREE.Vector3().lerpVectors(segOne, segTwo, 0.5));\n                    eraserBox.position.add(new this.THREE.Vector3().copy(upVector).multiplyScalar(heightDelta + boxSize / 2 - delta));\n                    eraserBox.updateMatrix();\n                    let heightEraserCSG = this.CSG.fromMesh(eraserBox);\n                    ellipsoidCSG = ellipsoidCSG.subtract(heightEraserCSG);\n                  } else {\n                    let heightDelta = midRadius - segmentHeight;\n                    let dir = segOne.clone().sub(segTwo).normalize();\n                    let eraserBox = new this.THREE.Mesh(new this.THREE.BoxGeometry(boxSize, boxSize, boxSize));\n                    let upVector = this.getMeshUpVector(eraserBox, dir);\n                    let delta = this.getDifferenceUpAndMid(upVector, new this.THREE.Vector3().lerpVectors(segOne, segTwo, 0.5));\n                    eraserBox.position.add(new this.THREE.Vector3().copy(upVector).multiplyScalar(boxSize / 2 - heightDelta + delta));\n                    eraserBox.updateMatrix();\n                    let heightEraserCSG = this.CSG.fromMesh(eraserBox);\n                    ellipsoidCSG = ellipsoidCSG.subtract(heightEraserCSG);\n                  }\n                }\n              } else {\n                let maxHeight = midRadius;\n\n                if (segmentHeight <= maxHeight) {\n                  let midNotNormalized = new this.THREE.Vector3().lerpVectors(segOne, segTwo, 0.5);\n\n                  if (midRadius - midNotNormalized.length() > segmentHeight) {\n                    let heightDelta = midRadius - segmentHeight;\n                    let dir = segOne.clone().sub(segTwo).normalize();\n                    let eraserBox = new this.THREE.Mesh(new this.THREE.BoxGeometry(boxSize, boxSize, boxSize));\n                    eraserBox.lookAt(dir);\n                    eraserBox.position.add(new this.THREE.Vector3().copy(midVector).multiplyScalar(heightDelta - boxSize / 2));\n                    eraserBox.updateMatrix();\n                    let heightEraserCSG = this.CSG.fromMesh(eraserBox);\n                    ellipsoidCSG = ellipsoidCSG.subtract(heightEraserCSG);\n                  } else {\n                    let midPlane = new this.THREE.Plane(midVector);\n                    let differenceOne = Math.abs(midPlane.distanceToPoint(midPoint)) - Math.abs(midPlane.distanceToPoint(segOne));\n                    let differenceTwo = Math.abs(midPlane.distanceToPoint(midPoint)) - Math.abs(midPlane.distanceToPoint(segTwo));\n                    let segmentOne = Math.abs(segmentHeight - differenceOne);\n                    let segmentTwo = Math.abs(segmentHeight - differenceTwo);\n                    let proportionOne = segmentOne / midRadius;\n                    let proportionTwo = segmentTwo / midRadius;\n                    let proportion = Math.max(proportionOne, proportionTwo);\n                    let vecOne = segOne.clone().normalize().multiplyScalar(segOne.length() * proportion);\n                    let vecTwo = segTwo.clone().normalize().multiplyScalar(segTwo.length() * proportion);\n                    vecOne = new this.THREE.Vector2(vecOne.x, vecOne.y);\n                    vecTwo = new this.THREE.Vector2(vecTwo.x, vecTwo.y);\n                    let vecMid = new this.THREE.Vector2(0, 0);\n                    let heightEraserPoints = [vecMid, vecOne, vecTwo];\n                    let heightEraserShape = new this.THREE.Shape(heightEraserPoints);\n                    let heightEraserGeo = new this.THREE.ExtrudeGeometry(heightEraserShape, {\n                      steps: 1,\n                      bevelEnabled: false,\n                      depth: boxSize\n                    });\n                    heightEraserGeo.translate(0, 0, -boxSize / 2);\n                    let heightEraserMesh = new this.THREE.Mesh(heightEraserGeo);\n                    let heightEraserCSG = this.CSG.fromMesh(heightEraserMesh);\n                    ellipsoidCSG = ellipsoidCSG.subtract(heightEraserCSG);\n                  }\n                }\n              }\n            }\n          }\n\n          ellipsoidMesh = this.CSG.toMesh(ellipsoidCSG, new this.THREE.Matrix4());\n        }\n      }\n\n      this.GraphicsThree3D.alignObjectWithVectors(ellipsoidMesh, centerPoint, directionVectorThree, directionVectorOne);\n      ellipsoidMesh.updateMatrix();\n      ellipsoidMesh.generationType = \"volume\"; ///\n\n      let linePairs = [];\n      this.WireframeGenerator.getRegularWireframePointPairs(ellipsoidMesh, Math.PI / 720).forEach(pair => linePairs.push([pair[0].clone().applyMatrix4(ellipsoidMesh.matrix), pair[1].clone().applyMatrix4(ellipsoidMesh.matrix)]));\n      let linePairsForOpaque = [];\n\n      if (this.segmentVectorsAreValid(ellipsoidData.segmentVector1, ellipsoidData.segmentVector2)) {\n        this.WireframeGenerator.getRegularWireframePointPairs(ellipsoidMesh, 20 * Math.PI / 180).forEach(pair => linePairsForOpaque.push([pair[0].clone().applyMatrix4(ellipsoidMesh.matrix), pair[1].clone().applyMatrix4(ellipsoidMesh.matrix)]));\n      }\n\n      this.WireframeGenerator.getVolumeWireframeData(ellipsoidMesh, linePairsForOpaque, linePairs, ellipsoidData.objectType); ///\n\n      return ellipsoidMesh;\n    }\n\n    getEllipsoidSegments(ellipsoidCSG, segmentVectorOne, segmentVectorTwo) {\n      let segOne = new this.THREE.Vector3();\n      let segTwo = new this.THREE.Vector3();\n      let maxDistanceOne = 0,\n          maxDistanceTwo = 0;\n      ellipsoidCSG.polygons.forEach(polygon => polygon.vertices.forEach(vertex => {\n        let localVertex = new this.THREE.Vector3(vertex.pos.x, vertex.pos.y, vertex.pos.z);\n        let dirOne = localVertex.clone().normalize().dot(segmentVectorOne.clone().normalize());\n        let distanceOne = segmentVectorOne.clone().dot(localVertex);\n\n        if (dirOne > 0.9999) {\n          if (distanceOne > maxDistanceOne) {\n            maxDistanceOne = distanceOne;\n            segOne.copy(localVertex);\n          }\n        }\n\n        let dirTwo = localVertex.clone().normalize().dot(segmentVectorTwo.clone().normalize());\n        let distanceTwo = segmentVectorTwo.clone().dot(localVertex);\n\n        if (dirTwo > 0.9999) {\n          if (distanceTwo > maxDistanceTwo) {\n            maxDistanceTwo = distanceTwo;\n            segTwo.copy(localVertex);\n          }\n        }\n      }));\n      return [segOne, segTwo];\n    }\n\n    getMeshUpVector(mesh, direction) {\n      let upObject = new this.THREE.Object3D();\n      upObject.position.copy(mesh.up);\n      mesh.add(upObject);\n      mesh.lookAt(direction);\n      mesh.updateMatrixWorld();\n      let upVector = upObject.getWorldPosition(new this.THREE.Vector3());\n      return upVector;\n    }\n\n    getDifferenceUpAndMid(up, mid) {\n      let midLength = mid.length();\n      let upLength = midLength * Math.cos(up.angleTo(mid));\n      let delta = midLength - upLength;\n      return delta;\n    }\n\n    makeEllipsoidMesh(radiusOne, radiusTwo, radiusThree) {\n      const DETAIL = 32;\n      let ellipsoidGeo = new this.THREE.SphereGeometry(radiusOne, DETAIL, DETAIL).applyMatrix4(new this.THREE.Matrix4().makeScale(1, radiusTwo / radiusOne, radiusThree / radiusOne));\n      let ellipsoidMesh = new this.THREE.Mesh(ellipsoidGeo);\n      return ellipsoidMesh;\n    }\n\n    segmentVectorsAreValid(segmentVector1, segmentVector2) {\n      return segmentVector1 && segmentVector2 && (segmentVector1.x || segmentVector1.y || segmentVector1.z) && (segmentVector2.x || segmentVector2.y || segmentVector2.z);\n    }\n\n  }\n\n  _exports.Ellipsoid = Ellipsoid;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Point\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.Point = void 0;\n\n  class Point {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.THREE = GraphicsThree3D.THREE;\n      this.utils = GraphicsThree3D.utils;\n      this.CSG = GraphicsThree3D.CSG;\n    }\n\n    drawPoint(pointData, materialProps) {\n      let pointProps = materialProps.point;\n      let lineProps = materialProps.line;\n      let pointType = pointData.objectGeneration.type;\n      let pointMesh;\n\n      if (pointType == 1) {\n        pointMesh = this.drawPointPlanar(pointData, pointProps);\n        pointMesh.generationType = \"point\";\n      } else if (pointType == 2) {\n        pointMesh = this.drawPointExtruded(pointData, lineProps);\n        pointMesh.generationType = \"line\";\n      } else {\n        pointMesh = this.drawPointRotated(pointData, lineProps);\n        pointMesh.generationType = \"line\";\n      }\n\n      return pointMesh;\n    }\n\n    drawPointPlanar(pointData, pointProps) {\n      let insertionPoint = pointData.insertionPoint;\n      let pointRadius = pointProps.size / 2;\n      let pointColor = pointProps.color;\n      let pointGeo = new this.THREE.SphereBufferGeometry(pointRadius, 32, 16);\n      let pointMaterial = this.utils.getMaterialFromColorProps(pointColor);\n      let pointMesh = new this.THREE.Mesh(pointGeo, pointMaterial);\n      pointMesh.position.set(insertionPoint.x, insertionPoint.y, insertionPoint.z);\n      return pointMesh;\n    }\n\n    drawPointExtruded(pointData, lineProps) {\n      let insertionPoint = pointData.insertionPoint;\n      let extrusionVector = pointData.objectGeneration.extrusionVector;\n      let [pointOne, pointTwo] = this.getExtrudedPointPoints(insertionPoint, extrusionVector);\n      let lineMesh = this.utils.drawConnectedLines([pointOne, pointTwo], lineProps);\n      return lineMesh;\n    }\n\n    getExtrudedPointPoints(insertionPoint, extrusionVector) {\n      let extrusion = this.utils.initVector3(extrusionVector);\n      let pointOne = this.utils.initVector3(insertionPoint);\n      let pointTwo = pointOne.clone().add(extrusion);\n      return [pointOne, pointTwo];\n    }\n\n    drawPointRotated(pointData, lineProps) {\n      let circlePoints = this.getRotatedPoints(pointData);\n      let lineMesh = this.utils.drawConnectedLines(circlePoints, lineProps);\n      return lineMesh;\n    }\n\n    getRotatedPoints(pointData) {\n      let insertionPoint = pointData.insertionPoint;\n      let rotationPoint = pointData.objectGeneration.rotationPoint;\n      let rotationAxis = this.utils.initVector3(pointData.objectGeneration.rotationAxis);\n      let rotationAngle = pointData.objectGeneration.rotationAngle * Math.PI / 180;\n      let rotationPitch = pointData.objectGeneration.rotationPitch;\n      let pivotPoint = new this.THREE.Object3D();\n      pivotPoint.position.set(rotationPoint.x, rotationPoint.y, rotationPoint.z);\n      let positionPoint = new this.THREE.Object3D();\n      positionPoint.position.set(insertionPoint.x, insertionPoint.y, insertionPoint.z);\n      pivotPoint.attach(positionPoint);\n      let startPoint = this.utils.initVector3(insertionPoint);\n      let circlePoints = [startPoint];\n      let positionVector = new this.THREE.Vector3(); // dummy vector for obtaining results\n\n      let numOfSegments = 64 * rotationAngle / (Math.PI * 2);\n\n      for (let i = 0; i < numOfSegments; i++) {\n        pivotPoint.rotateOnAxis(rotationAxis, rotationAngle / numOfSegments);\n        pivotPoint.updateMatrixWorld();\n        let newPoint = new this.THREE.Vector3().add(positionPoint.getWorldPosition(positionVector));\n        newPoint.add(rotationAxis.clone().normalize().multiplyScalar((i + 1) * rotationPitch / numOfSegments));\n        circlePoints.push(newPoint);\n      }\n\n      return circlePoints;\n    }\n\n  }\n\n  _exports.Point = Point;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Polygon\", [\"exports\", \"m08-2020/lib/ThreeExtensions/RotatedGeometry\", \"m08-2020/lib/ThreeExtensions/PlanarRotationPointsGenerator\", \"m08-2020/lib/ThreeExtensions/PlanarExtrusionPointsGenerator\"], function (_exports, _RotatedGeometry, _PlanarRotationPointsGenerator, _PlanarExtrusionPointsGenerator) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.Polygon = void 0;\n\n  class Polygon {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.THREE = GraphicsThree3D.THREE;\n      this.utils = GraphicsThree3D.utils;\n      this.CSG = GraphicsThree3D.CSG;\n      this.WireframeGenerator = GraphicsThree3D.WireframeGenerator;\n    }\n\n    drawPolygon(polygonData) {\n      let polygon;\n      let isPlanar = this.polygonIsPlanar(polygonData);\n\n      if (polygonData.objectGeneration.type === 1) {\n        polygon = this.drawPolygonPlanar(polygonData);\n        polygon.generationType = \"area\";\n      } else if (polygonData.objectGeneration.type === 2) {\n        if (!isPlanar) {\n          polygon = this.drawPolygonExtruded(polygonData);\n          polygon.generationType = \"volume\";\n        } else {\n          polygon = this.drawPolygonExtrudedPlanar(polygonData);\n          polygon.generationType = \"area\";\n        }\n      } else {\n        if (isPlanar) {\n          polygon = this.drawPolygonRotatedPlanar(polygonData);\n          polygon.generationType = \"area\";\n        } else {\n          polygon = this.drawPolygonRotated(polygonData);\n          polygon.generationType = \"volume\";\n        }\n      }\n\n      return polygon;\n    }\n\n    drawPolygonPlanar(polygonData) {\n      let polygonDepth = 0.01;\n      let extrusionVector = new this.THREE.Vector3(0, 0, polygonDepth);\n      let extrusionNormalized = extrusionVector.clone().normalize();\n      let pts = this.getPolygonPlanarPoints(polygonData);\n      let [midVector, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(pts, extrusionNormalized);\n      pts.forEach(point => {\n        point.sub(midVector);\n        point.applyEuler(eulerOne);\n      });\n      let shapePts = pts.map(point => new this.THREE.Vector2(point.x, point.y));\n      let shape = new this.THREE.Shape(shapePts);\n      extrusionVector.applyEuler(eulerOne);\n      extrusionNormalized.applyEuler(eulerOne); // extrusionVector.z *= -1;\n\n      let extrudeSettings = {\n        depth: extrusionVector.z,\n        bevelEnabled: false\n      };\n      let geometry = new this.THREE.ExtrudeGeometry(shape, extrudeSettings); // geometry.translate(0, 0, -extrusionVector.z);\n\n      let polygon = new this.THREE.Mesh(geometry);\n      polygon.position.add(midVector);\n      polygon.updateMatrix();\n      polygon.setRotationFromEuler(eulerTwo);\n      return polygon;\n    }\n\n    drawPolygonExtruded(polygonData) {\n      let extrusionVector = this.utils.initVector3(polygonData.objectGeneration.extrusionVector);\n      let extrusionNormalized = extrusionVector.clone().normalize();\n      let pts = this.getPolygonPlanarPoints(polygonData);\n      let [midVector, eulerOne, eulerTwo, crossVector] = this.GraphicsThree3D.getRotationParameters(pts, extrusionNormalized);\n      pts.forEach(point => {\n        point.sub(midVector);\n        point.applyEuler(eulerOne);\n      });\n      extrusionVector.applyEuler(eulerOne); // TODO: I am not sure this logic is correct\n\n      crossVector.applyEuler(eulerOne);\n      let skewParams = this.utils.getSkewParams(extrusionVector);\n      let polygonDepth = extrusionVector.z;\n      let shapePts = pts.map(point => new this.THREE.Vector2(point.x, point.y));\n      let geometry = this.GraphicsThree3D.makeExtrudeGeoRaw(shapePts, polygonDepth); // TODO: I am not sure this logic is correct\n\n      if (crossVector.dot(new this.THREE.Vector3(0, 0, -1)) > 0) {\n        geometry.translate(0, 0, -polygonDepth);\n      }\n\n      this.utils.skewExtrudedGeometry(geometry, skewParams);\n      let polygon = new this.THREE.Mesh(geometry);\n      polygon.position.add(midVector);\n      polygon.setRotationFromEuler(eulerTwo);\n      polygon.updateMatrix();\n      return polygon;\n    }\n\n    drawPolygonExtrudedPlanar(polygonData) {\n      let zAxis = new this.THREE.Vector3(0, 0, 1);\n      let polygonPoints = this.getPolygonPlanarPoints(polygonData);\n      let [midVector, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(polygonPoints, zAxis);\n      polygonPoints.forEach(point => {\n        point.sub(midVector);\n        point.applyEuler(eulerOne);\n      });\n      let extrusionVector = this.utils.initVector3(polygonData.objectGeneration.extrusionVector).applyEuler(eulerOne);\n      let shapePts = new _PlanarExtrusionPointsGenerator.PlanarExtrusionPointsGenerator(polygonPoints, extrusionVector).extrudedPoints;\n      let shape = new this.THREE.Shape(shapePts);\n      let geometry = new this.THREE.ExtrudeGeometry(shape, {\n        depth: 0.01,\n        bevelEnabled: false\n      });\n      let polygon = new this.THREE.Mesh(geometry);\n      polygon.position.add(midVector);\n      polygon.setRotationFromEuler(eulerTwo);\n      polygon.updateMatrix();\n      return polygon;\n    }\n\n    drawPolygonRotated(polygonData) {\n      let pts = this.getPolygonPlanarPoints(polygonData);\n      let rotatedGeometry = new _RotatedGeometry.RotatedGeometry(pts.map(pt => pt.clone()), {\n        rotationPoint: this.utils.initVector3(polygonData.objectGeneration.rotationPoint),\n        rotationAxis: this.utils.initVector3(polygonData.objectGeneration.rotationAxis).normalize(),\n        rotationAngle: polygonData.objectGeneration.rotationAngle * Math.PI / 180,\n        rotationPitch: polygonData.objectGeneration.rotationPitch\n      });\n      let polygon = new this.THREE.Mesh(rotatedGeometry); ///\n\n      let linePairs = [];\n      this.WireframeGenerator.getRegularWireframePointPairs(polygon, Math.PI / 6).forEach(pair => linePairs.push([pair[0].clone().applyMatrix4(polygon.matrix), pair[1].clone().applyMatrix4(polygon.matrix)]));\n      this.WireframeGenerator.getVolumeWireframeData(polygon, linePairs, linePairs, polygonData.objectType); ///\n\n      return polygon;\n    }\n\n    drawPolygonRotatedPlanar(polygonData) {\n      console.log(\"here we are\", polygonData);\n      let rotationPoint = this.utils.initVector3(polygonData.objectGeneration.rotationPoint);\n      let rotationAxis = this.utils.initVector3(polygonData.objectGeneration.rotationAxis).normalize();\n      let rotationAngle = polygonData.objectGeneration.rotationAngle * Math.PI / 180;\n      let rotationPitch = polygonData.objectGeneration.rotationPitch;\n      let polygonPoints = this.getPolygonPlanarPoints(polygonData);\n      let zeroPoint = new this.THREE.Vector3();\n      let yAxis = new this.THREE.Vector3(0, 1, 0);\n      let zAxis = new this.THREE.Vector3(0, 0, 1);\n      let [_, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(polygonPoints, zAxis);\n      polygonPoints.forEach(point => {\n        point.sub(rotationPoint);\n        point.applyEuler(eulerOne);\n      });\n      if (rotationAxis.applyEuler(eulerOne).dot(zAxis) < 0) rotationAngle *= -1; /// -->\n\n      polygonPoints = new _PlanarRotationPointsGenerator.PlanarRotationPointsGenerator(polygonPoints, {\n        rotationAngle,\n        rotationPitch\n      }).rotatedPoints; /// <--\n      // for ( let i = 0; i < polygonPoints.length - 1; i++ ) polygonPoints[ i ].nextPoint = polygonPoints[ i + 1 ];\n      // polygonPoints[ polygonPoints.length - 1 ].nextPoint = polygonPoints[ 0 ];\n      // let distancePlaneNormal = new this.THREE.Vector3().crossVectors( zAxis, yAxis );\n      // let { minPt, maxPt } = polygonPoints.reduce(({ maxDistance, maxPt, minDistance, minPt }, pt) => {\n      //   let projectedPt = pt.clone().projectOnVector( distancePlaneNormal );\n      //   let distance = pt.distanceTo( zeroPoint );\n      //   if ( projectedPt.dot( distancePlaneNormal ) < 0 ) distance *= -1;\n      //   if ( distance > maxDistance ) { maxDistance = distance; maxPt.copy( pt ); }\n      //   if ( distance < minDistance ) { minDistance = distance; minPt.copy( pt ); }\n      //   return { maxDistance, maxPt, minDistance, minPt };\n      // }, {\n      //   maxDistance: -Infinity,\n      //   minDistance: Infinity,\n      //   maxPt: new this.THREE.Vector3(),\n      //   minPt: new this.THREE.Vector3()\n      // });\n      // console.log(maxPt, minPt);\n\n      let shapePts = polygonPoints.map(point => new this.THREE.Vector3(point.x, point.y, 0));\n      let shape = new this.THREE.Shape(shapePts);\n      let extrudeSettings = {\n        depth: -0.01,\n        bevelEnabled: false\n      };\n      let geometry = new this.THREE.ExtrudeGeometry(shape, extrudeSettings);\n      let polygon = new this.THREE.Mesh(geometry);\n      polygon.position.add(rotationPoint);\n      polygon.setRotationFromEuler(eulerTwo);\n      polygon.updateMatrix();\n      console.log(geometry);\n      return polygon;\n    }\n\n    getPolygonPlanarPoints(polygonData) {\n      let points = [];\n\n      for (let c = 0; c < polygonData.points.length; c++) {\n        let x = polygonData.points[c].x;\n        let y = polygonData.points[c].y;\n        let z = polygonData.points[c].z;\n        points.push(new this.THREE.Vector3(x, y, z));\n      }\n\n      return points;\n    }\n\n    polygonIsPlanar(polygonData) {\n      return polygonData.objectGeneration.type === 1 || polygonData.objectGeneration.type === 2 && this.utils.vectorIsZero(polygonData.objectGeneration.extrusionVector) || polygonData.objectGeneration.type === 2 && this.GraphicsThree3D.objectExtrudesPlanar(polygonData) || polygonData.objectGeneration.type === 3 && this.GraphicsThree3D.objectRotatesPlanar(polygonData);\n    }\n\n  }\n\n  _exports.Polygon = Polygon;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Polyline\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.Polyline = void 0;\n\n  class Polyline {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.THREE = GraphicsThree3D.THREE;\n      this.utils = GraphicsThree3D.utils;\n      this.CSG = GraphicsThree3D.CSG;\n      this.WireframeGenerator = GraphicsThree3D.WireframeGenerator;\n    }\n\n    drawPolyline(lineData, materialProps) {\n      let lineProps = materialProps.line;\n      let lineType = lineData.objectGeneration.type;\n      let lineMesh;\n\n      if (lineType == 1) {\n        lineMesh = this.drawPolylinePlanar(lineData, lineProps);\n        lineMesh.generationType = \"line\";\n      } else if (lineType == 2) {\n        lineMesh = this.drawPolylineExtruded(lineData);\n        lineMesh.generationType = \"area\";\n      } else if (lineType == 3) {\n        lineMesh = this.drawPolylineRotated(lineData);\n        lineMesh.generationType = \"area\";\n      }\n\n      return lineMesh;\n    }\n\n    drawPolylinePlanar(lineData, lineProps) {\n      let linePoints = lineData.points;\n      let lineVerticies = [];\n      linePoints.forEach(point => lineVerticies.push(this.utils.initVector3(point)));\n      let lineMesh = this.utils.drawConnectedLines(lineVerticies, lineProps);\n      return lineMesh;\n    }\n\n    drawPolylineExtruded(lineData) {\n      let polylineDepth = 0.01;\n      let depthExtrusion = new this.THREE.Vector3(0, 0, polylineDepth);\n      let extrusionNormalized = depthExtrusion.clone().normalize();\n      let linePoints = lineData.points;\n      let extrusionVector = lineData.objectGeneration.extrusionVector;\n      let basePoints = [];\n      let extrudePoints = [];\n      linePoints.forEach(point => {\n        let originVector = new this.THREE.Vector3(point.x, point.y, point.z);\n        let extrudedVector = new this.THREE.Vector3(point.x + extrusionVector.x, point.y + extrusionVector.y, point.z + extrusionVector.z);\n        basePoints.push(originVector);\n        extrudePoints.push(extrudedVector);\n      });\n      extrudePoints = extrudePoints.reverse();\n      let points = basePoints.concat(extrudePoints); // this.WireframeGenerator.getPlanarPoints(points.map(point => point.clone()), lineData.objectType);\n\n      let [midVector, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(points, extrusionNormalized);\n      points.forEach(point => {\n        // this.GraphicsThree3D.wireframePoints.push(point.clone());\n        point.sub(midVector);\n        point.applyEuler(eulerOne);\n      });\n      let shapePts = points.map(point => new this.THREE.Vector2(point.x, point.y));\n      let shape = new this.THREE.Shape(shapePts);\n      depthExtrusion.applyEuler(eulerOne);\n      extrusionNormalized.applyEuler(eulerOne);\n      let extrudeSettings = {\n        depth: depthExtrusion.z,\n        bevelEnabled: false\n      };\n      let geometry = new this.THREE.ExtrudeGeometry(shape, extrudeSettings);\n      let areaMesh = new this.THREE.Mesh(geometry);\n      areaMesh.position.add(midVector);\n      areaMesh.updateMatrix();\n      areaMesh.setRotationFromEuler(eulerTwo);\n      return areaMesh;\n    }\n\n    drawPolylineRotated(lineData) {\n      let linePoints = lineData.points;\n      let rotationPoint = lineData.objectGeneration.rotationPoint;\n      let rotationAxis = this.utils.initVector3(lineData.objectGeneration.rotationAxis);\n      let rotationAngle = lineData.objectGeneration.rotationAngle * Math.PI / 180;\n      let botPoints = [];\n      let topPoints = [];\n      let startPoints = [];\n      let endPoints = [];\n      let dummyVector = new this.THREE.Vector3();\n      linePoints.forEach((point, index) => {\n        botPoints.push(this.utils.initVector3(point));\n\n        if (index > 0 && index < linePoints.length - 1) {\n          let topObject = new this.THREE.Object3D();\n          topObject.position.set(point.x, point.y, point.z);\n          let pivotPoint = new this.THREE.Object3D();\n          pivotPoint.position.set(rotationPoint.x, rotationPoint.y, rotationPoint.z);\n          pivotPoint.attach(topObject);\n          pivotPoint.rotateOnAxis(rotationAxis, rotationAngle);\n          pivotPoint.updateMatrixWorld();\n          let newTopPoint = topObject.getWorldPosition(dummyVector).clone();\n          topPoints.push(newTopPoint);\n        }\n      });\n      let startObject = new this.THREE.Object3D();\n      startObject.position.set(linePoints[0].x, linePoints[0].y, linePoints[0].z);\n      let endObject = new this.THREE.Object3D();\n      endObject.position.set(linePoints[linePoints.length - 1].x, linePoints[linePoints.length - 1].y, linePoints[linePoints.length - 1].z);\n      let pivotPoint = new this.THREE.Object3D();\n      pivotPoint.position.set(rotationPoint.x, rotationPoint.y, rotationPoint.z);\n      pivotPoint.attach(startObject);\n      pivotPoint.attach(endObject);\n      let numOfSegments = Math.abs(64 * rotationAngle / (Math.PI * 2));\n\n      for (let i = 0; i < numOfSegments; i++) {\n        pivotPoint.rotateOnAxis(rotationAxis, rotationAngle / numOfSegments);\n        pivotPoint.updateMatrixWorld();\n        let newStartPoint = startObject.getWorldPosition(dummyVector).clone();\n        startPoints.push(newStartPoint);\n        let newEndPoint = endObject.getWorldPosition(dummyVector).clone();\n        endPoints.push(newEndPoint);\n      }\n\n      topPoints.reverse();\n      startPoints.reverse();\n      let polylineDepth = 0.01;\n      let extrusionVector = new this.THREE.Vector3(0, 0, polylineDepth);\n      let extrusionNormalized = extrusionVector.clone().normalize();\n      let pts = botPoints.concat(endPoints).concat(topPoints).concat(startPoints); // this.WireframeGenerator.getPlanarPoints(pts.map(point => point.clone()), lineData.objectType);\n\n      let [midVector, eulerOne, eulerTwo] = this.GraphicsThree3D.getRotationParameters(pts, extrusionNormalized);\n      pts.forEach(point => {\n        // this.GraphicsThree3D.wireframePoints.push(point.clone());\n        point.sub(midVector);\n        point.applyEuler(eulerOne);\n      });\n      let shapePts = pts.map(point => new this.THREE.Vector2(point.x, point.y));\n      let shape = new this.THREE.Shape(shapePts);\n      extrusionVector.applyEuler(eulerOne);\n      extrusionNormalized.applyEuler(eulerOne);\n      let extrudeSettings = {\n        depth: extrusionVector.z,\n        bevelEnabled: false\n      };\n      let geometry = new this.THREE.ExtrudeGeometry(shape, extrudeSettings);\n      let areaMesh = new this.THREE.Mesh(geometry);\n      areaMesh.position.add(midVector);\n      areaMesh.updateMatrix();\n      areaMesh.setRotationFromEuler(eulerTwo);\n      return areaMesh;\n    }\n\n  }\n\n  _exports.Polyline = Polyline;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingObjectLoader\", [\"exports\", \"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Point\", \"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Polyline\", \"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Ellipse\", \"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Polygon\", \"m08-2020/lib/FigureLoaders/DrawingObjectComponents/Ellipsoid\", \"m08-2020/lib/FigureLoaders/DrawingObjectComponents/ComplexVolume\", \"m08-2020/lib/Utils/BooleanOperations\"], function (_exports, _Point, _Polyline, _Ellipse, _Polygon, _Ellipsoid, _ComplexVolume, BooleanOperations) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.DrawingObjectLoader = void 0;\n  // TODO: Move this another place?\n  const LINE_MIN_THICKNESS = 0.4; //\n\n  class DrawingObjectLoader {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.THREE = GraphicsThree3D.THREE;\n      this.utils = GraphicsThree3D.utils;\n      this.WireframeGenerator = GraphicsThree3D.WireframeGenerator;\n      this.Ellipsoid = new _Ellipsoid.Ellipsoid(GraphicsThree3D);\n      this.Point = new _Point.Point(GraphicsThree3D);\n      this.Polyline = new _Polyline.Polyline(GraphicsThree3D);\n      this.Ellipse = new _Ellipse.Ellipse(GraphicsThree3D);\n      this.Polygon = new _Polygon.Polygon(GraphicsThree3D);\n      this.ComplexVolume = new _ComplexVolume.ComplexVolume(GraphicsThree3D);\n    }\n\n    drawPoints(points, properties, positivesAndNegatives) {\n      points.forEach(point => {\n        if (point.objectType > 0 && point.objectType < 3) {\n          let pointMesh = this.Point.drawPoint(point, properties);\n          if (point.objectGeneration.type === 1) this.addToPosAndNeg(pointMesh, point, positivesAndNegatives, \"point\");else if (point.objectGeneration.type === 2 || point.objectGeneration.type === 3) this.addToPosAndNeg(pointMesh, point, positivesAndNegatives, \"line\");\n        }\n      });\n    }\n\n    drawPolylines(polylines, properties, positivesAndNegatives) {\n      polylines.forEach(polyline => {\n        if (polyline.objectType > 0 && polyline.objectType < 3) {\n          let lineMesh = this.Polyline.drawPolyline(polyline, properties);\n          if (polyline.objectGeneration.type === 1) this.addToPosAndNeg(lineMesh, polyline, positivesAndNegatives, \"line\");else if (polyline.objectGeneration.type === 2 || polyline.objectGeneration.type === 3) this.addToPosAndNeg(lineMesh, polyline, positivesAndNegatives, \"area\");\n        }\n      });\n    }\n\n    drawEllipses(ellipses, positivesAndNegatives) {\n      ellipses.forEach(ellipse => {\n        console.log(ellipse);\n\n        if (ellipse.objectType > 0 && ellipse.objectType < 3) {\n          let ellipseMesh = this.Ellipse.drawEllipse(ellipse);\n          ellipseMesh.updateMatrix();\n\n          if (ellipse.objectGeneration.type === 1 || ellipse.objectGeneration.type === 2 && this.GraphicsThree3D.objectExtrudesPlanar(ellipse, true) || ellipse.objectGeneration.type === 3 && !ellipse.objectGeneration.rotationAngle || ellipse.objectGeneration.type === 3 && this.GraphicsThree3D.objectRotatesPlanar(ellipse, true)) {\n            this.addToPosAndNeg(ellipseMesh, ellipse, positivesAndNegatives, \"area\");\n          } else {\n            if (ellipse.objectGeneration.type === 2) this.addToPosAndNeg(ellipseMesh, ellipse, positivesAndNegatives, \"volumeRounded\");else if (ellipse.objectGeneration.type === 3) this.addToPosAndNeg(ellipseMesh, ellipse, positivesAndNegatives, \"volumeRounded\");\n          }\n        }\n      });\n    }\n\n    drawPolygons(polygons, positivesAndNegatives) {\n      polygons.forEach(polygon => {\n        if (polygon.objectType > 0 && polygon.objectType < 3 && polygon.objectGeneration.type > 0 && polygon.objectGeneration.type < 4) {\n          let polygonMesh = this.Polygon.drawPolygon(polygon);\n          if (this.Polygon.polygonIsPlanar(polygon)) this.addToPosAndNeg(polygonMesh, polygon, positivesAndNegatives, \"area\");else {\n            if (polygon.objectGeneration.type === 2) this.addToPosAndNeg(polygonMesh, polygon, positivesAndNegatives, \"volumeRegular\");else if (polygon.objectGeneration.type === 3) this.addToPosAndNeg(polygonMesh, polygon, positivesAndNegatives, \"volumeRounded\");\n          }\n        }\n      });\n    }\n\n    drawEllipsoids(ellipsoids, positivesAndNegatives) {\n      ellipsoids.forEach(ellipsoid => {\n        if (ellipsoid.objectType > 0 && ellipsoid.objectType < 3) {\n          let ellipsoidMesh = this.Ellipsoid.drawEllipsoid(ellipsoid);\n          this.addToPosAndNeg(ellipsoidMesh, ellipsoid, positivesAndNegatives, \"volumeRounded\");\n        }\n      });\n    }\n\n    drawComplexVolumes(drawingObject, jsonData) {\n      let components = drawingObject.components;\n      let properties = drawingObject.properties;\n      let multilayeredObjects = {\n        positives: [],\n        negatives: []\n      };\n      let wireframes = [];\n      if (components.polygons) wireframes.push(...this.ComplexVolume.drawMultilayeredPolygons(components.polygons, properties, multilayeredObjects));\n      if (components.ellipses) wireframes.push(...this.ComplexVolume.drawMultilayeredEllipses(components.ellipses, properties, multilayeredObjects));\n      if (components.ellipsoids) wireframes.push(...this.ComplexVolume.drawMultilayeredEllipsoids(components.ellipsoids, properties, multilayeredObjects));\n      this.ComplexVolume.addMultilayeredObjectsToScene(multilayeredObjects, wireframes, properties, drawingObject.insertionPoints, jsonData, drawingObject);\n    }\n\n    drawRegularObjects(drawingObject, jsonData) {\n      if (drawingObject.insertionPoints) {\n        let components = drawingObject.components;\n        let properties = drawingObject.properties;\n        let positivesAndNegatives = {\n          area: {\n            positiveObjects: [],\n            negativeObjects: []\n          },\n          volumeRegular: {\n            positiveObjects: [],\n            negativeObjects: []\n          },\n          volumeRounded: {\n            positiveObjects: [],\n            negativeObjects: []\n          },\n          point: {\n            positiveObjects: [],\n            negativeObjects: []\n          },\n          line: {\n            positiveObjects: [],\n            negativeObjects: []\n          }\n        };\n        if (components.points) this.drawPoints(components.points, properties, positivesAndNegatives);\n        if (components.polylines) this.drawPolylines(components.polylines, properties, positivesAndNegatives);\n        if (components.ellipses) this.drawEllipses(components.ellipses, positivesAndNegatives);\n        if (components.polygons) this.drawPolygons(components.polygons, positivesAndNegatives);\n        if (components.ellipsoids) this.drawEllipsoids(components.ellipsoids, positivesAndNegatives);\n        let areas = positivesAndNegatives.area;\n        let volumesRegular = positivesAndNegatives.volumeRegular;\n        let volumesRounded = positivesAndNegatives.volumeRounded;\n        let points = positivesAndNegatives.point;\n        let lines = positivesAndNegatives.line;\n        this.generateAreas(areas, drawingObject, properties, jsonData); ///\n\n        this.generateVolumes(volumesRegular, volumesRounded, drawingObject, properties, jsonData); ///\n\n        this.generatePoints(points, drawingObject, properties, jsonData);\n        this.generateLines(lines, drawingObject, properties, jsonData);\n      }\n    }\n\n    generateAreas(areas, drawingObject, properties, jsonData) {\n      let areaPos = areas.positiveObjects;\n      let areaNeg = areas.negativeObjects;\n\n      if (areaPos.length > 0) {\n        let positiveObject = BooleanOperations.applyCSG(areaPos, areaNeg);\n        let objectMaterial = this.GraphicsThree3D.getAreaMaterial(positiveObject, properties);\n\n        if (objectMaterial !== null) {\n          positiveObject.material = objectMaterial;\n          positiveObject.material.side = this.THREE.FrontSide;\n          let object = positiveObject;\n          let objectTransparent = this.GraphicsThree3D.makeTransparentClone(object);\n          objectTransparent.applyMatrix4(object.matrix);\n          this.addToDimChainCollisionDetection(positiveObject, drawingObject.insertionPoints);\n          object.stencilNeeded = true;\n          object.addToDXF = true;\n          let lineProps = { ...properties.line,\n            thickness: properties.line.thickness >= LINE_MIN_THICKNESS ? properties.line.thickness : LINE_MIN_THICKNESS\n          };\n          this.WireframeGenerator.applyWireframesArea(object, objectTransparent, lineProps, drawingObject);\n          this.GraphicsThree3D.addObjectToScene(object, objectTransparent, drawingObject.insertionPoints, jsonData, \"area\", \"drawingObject\", drawingObject);\n        }\n      }\n    }\n\n    generateVolumes(volumesRegular, volumesRounded, drawingObject, properties, jsonData) {\n      let volumePosRegular = volumesRegular.positiveObjects;\n      let volumeNegRegular = volumesRegular.negativeObjects;\n      let volumePosRounded = volumesRounded.positiveObjects;\n      let volumeNegRounded = volumesRounded.negativeObjects;\n      let positiveObjectRegular = volumePosRegular.length > 0 ? BooleanOperations.applyCSG(volumePosRegular, volumeNegRegular) : null;\n      let positiveObjectRounded = volumePosRounded.length > 0 ? BooleanOperations.applyCSG(volumePosRounded, volumeNegRounded) : null;\n      let positiveObject;\n      if (positiveObjectRegular && positiveObjectRounded) positiveObject = BooleanOperations.doCSG(positiveObjectRegular, positiveObjectRounded, \"union\");else if (positiveObjectRegular && !positiveObjectRounded && volumeNegRounded.length > 0) {\n        positiveObject = positiveObjectRegular;\n        volumeNegRounded.forEach(negativeObject => positiveObject = BooleanOperations.doCSG(positiveObject, negativeObject, \"subtract\"));\n      } else if (positiveObjectRegular && !positiveObjectRounded) positiveObject = positiveObjectRegular;else if (!positiveObjectRegular && positiveObjectRounded && volumeNegRegular.length > 0) {\n        positiveObject = positiveObjectRounded;\n        volumeNegRegular.forEach(negativeObject => positiveObject = BooleanOperations.doCSG(positiveObject, negativeObject, \"subtract\"));\n      } else if (!positiveObjectRegular && positiveObjectRounded) positiveObject = positiveObjectRounded;else positiveObject = null;\n\n      if (positiveObject) {\n        ///\n        volumeNegRegular.forEach(negativeObject => positiveObject = BooleanOperations.doCSG(positiveObject, negativeObject, \"subtract\"));\n        volumeNegRounded.forEach(negativeObject => positiveObject = BooleanOperations.doCSG(positiveObject, negativeObject, \"subtract\")); ///\n\n        let objectMaterial = this.GraphicsThree3D.getVolumeMaterialsIndexFaces(positiveObject, properties); // objectMaterial.forEach( mat => mat.wireframe = true );\n\n        if (objectMaterial !== null) {\n          objectMaterial.forEach(mat => mat.side = this.THREE.FrontSide);\n          positiveObject.material = objectMaterial;\n          let [doubleSideObject, frontSideObject, backSideObject] = this.GraphicsThree3D.getThreeSideFaceObjects(positiveObject);\n          this.addToDimChainCollisionDetection(positiveObject, drawingObject.insertionPoints);\n          this.GraphicsThree3D.indexMeshFaces(frontSideObject, properties);\n          this.GraphicsThree3D.indexMeshFaces(backSideObject, properties);\n          let objectTransparent = this.GraphicsThree3D.makeTransparentClone(positiveObject);\n          let geo = positiveObject.geometry.clone();\n          backSideObject.renderOrder = 0; // DepthClear mesh\n\n          let depthClearMesh = new this.THREE.Mesh(geo, objectMaterial);\n          depthClearMesh.applyMatrix4(positiveObject.matrix);\n          depthClearMesh.renderOrder = -100;\n\n          depthClearMesh.onBeforeRender = function (renderer) {\n            renderer.clearDepth();\n          };\n\n          this.GraphicsThree3D.addObjectToScene(depthClearMesh, objectTransparent, drawingObject.insertionPoints, jsonData, \"volume\", \"drawingObject\", drawingObject); // FrontSide material mesh\n\n          frontSideObject.stencilNeeded = true;\n          frontSideObject.addToDXF = true;\n          frontSideObject.dxfLayer = `drawingObject_${drawingObject.id}`;\n\n          if (positiveObjectRegular) {\n            let linePairs = this.WireframeGenerator.getRegularWireframePointPairs(positiveObjectRegular);\n            linePairs = linePairs.map(pair => [pair[0].clone().applyMatrix4(positiveObjectRegular.matrix), pair[1].clone().applyMatrix4(positiveObjectRegular.matrix)]);\n            this.WireframeGenerator.getVolumeWireframeData(positiveObjectRegular, linePairs, linePairs, 1);\n          }\n\n          let lineProps = { ...properties.line,\n            thickness: properties.line.thickness >= LINE_MIN_THICKNESS ? properties.line.thickness : LINE_MIN_THICKNESS\n          };\n          this.WireframeGenerator.applyWireframesVolume(frontSideObject, objectTransparent, lineProps, drawingObject);\n          this.GraphicsThree3D.addObjectToScene(frontSideObject, objectTransparent, drawingObject.insertionPoints, jsonData, \"volume\", \"drawingObject\", drawingObject); // BackSide material mesh\n\n          this.GraphicsThree3D.addObjectToScene(backSideObject, objectTransparent, drawingObject.insertionPoints, jsonData, \"volume\", \"drawingObject\", drawingObject);\n        }\n      }\n    }\n\n    generatePoints(points, drawingObject, properties, jsonData) {\n      let pointPos = points.positiveObjects;\n      let pointNeg = points.negativeObjects;\n\n      if (pointPos.length > 0) {\n        let positiveObject = BooleanOperations.applyCSG(pointPos, pointNeg);\n        let objectMaterial = this.GraphicsThree3D.getPointMaterial(properties);\n\n        if (objectMaterial !== null) {\n          positiveObject.material = objectMaterial;\n          let object = positiveObject;\n          let objectTransparent = null;\n          this.addToDimChainCollisionDetection(positiveObject, drawingObject.insertionPoints);\n          this.GraphicsThree3D.addObjectToScene(object, objectTransparent, drawingObject.insertionPoints, jsonData, \"point\", \"drawingObject\", drawingObject);\n          this.addPointObjectsToDXF(drawingObject);\n        }\n      }\n    }\n\n    generateLines(lines, drawingObject, properties, jsonData) {\n      // TODO: AddLines back to dim chain collision detection\n      let linePos = lines.positiveObjects;\n      let lineNeg = lines.negativeObjects;\n\n      if (linePos.length > 0) {\n        linePos.forEach(line => {\n          // let objectMaterial = this.GraphicsThree3D.getlineMeshMaterial(properties);\n          if (line.material !== null) {\n            // line.material = objectMaterial;\n            let object = line;\n            object.renderOrder = -6;\n            let objectTransparent = null; // this.addToDimChainCollisionDetection(line, drawingObject.insertionPoints);\n\n            this.GraphicsThree3D.addObjectToScene(object, objectTransparent, drawingObject.insertionPoints, jsonData, \"line\", \"drawingObject\", drawingObject);\n            this.addLineObjectsToDXF(drawingObject);\n          }\n        }); // let positiveObject = BooleanOperations.applyCSG(linePos, lineNeg);\n        // let objectMaterial = this.GraphicsThree3D.getlineMeshMaterial(properties);\n        // if (objectMaterial !== null) {\n        //   positiveObject.material = objectMaterial;\n        //   let object = positiveObject;\n        //   object.renderOrder = -6;\n        //   let objectTransparent = null;\n        //   this.addToDimChainCollisionDetection(positiveObject, drawingObject.insertionPoints);\n        //   this.GraphicsThree3D.addObjectToScene(object, objectTransparent, drawingObject.insertionPoints, jsonData, \"line\", \"drawingObject\", drawingObject);\n        //   this.addLineObjectsToDXF(drawingObject);\n        // }\n      }\n    }\n\n    addLineObjectsToDXF(lineData) {\n      let insertionPoints = lineData.insertionPoints;\n      let points = lineData.components.points;\n      let polylines = lineData.components.polylines;\n      insertionPoints.forEach(insertionPoint => {\n        let insertionVector = insertionPoint.insertionVector;\n        if (points) points.forEach(point => {\n          if (point.objectType === 1) {\n            if (point.objectGeneration.type === 2) {\n              let pointPair = this.Point.getExtrudedPointPoints(point.insertionPoint, point.objectGeneration.extrusionVector);\n              if (insertionPoint.rotationAngle) pointPair = pointPair.map(point => this.utils.applyRotationToVector(point, insertionPoint));\n              pointPair.forEach(point => point.add(insertionVector));\n              this.GraphicsThree3D.dxfGenerator.lineObjectsData.push({\n                id: lineData.id,\n                properties: lineData.properties.line,\n                pointPairs: [pointPair]\n              });\n            } else if (point.objectGeneration.type === 3) {\n              let circlePoints = this.Point.getRotatedPoints(point);\n              if (insertionPoint.rotationAngle) circlePoints = circlePoints.map(point => this.utils.applyRotationToVector(point, insertionPoint));\n              circlePoints.forEach(point => point.add(insertionVector));\n              let circlePointPairs = [];\n\n              for (let i = 0; i < circlePoints.length - 1; i++) circlePointPairs.push([circlePoints[i], circlePoints[i + 1]]);\n\n              this.GraphicsThree3D.dxfGenerator.lineObjectsData.push({\n                id: lineData.id,\n                properties: lineData.properties.line,\n                pointPairs: circlePointPairs\n              });\n            }\n          }\n        });\n        if (polylines) polylines.forEach(polyline => {\n          if (polyline.objectType === 1 && polyline.objectGeneration.type === 1) {\n            let polylinePoints = polyline.points.map(point => this.utils.initVector3(point));\n            if (insertionPoint.rotationAngle) polylinePoints = polylinePoints.map(point => this.utils.applyRotationToVector(point, insertionPoint));\n            polylinePoints.forEach(point => point.add(insertionVector));\n            let pointPairs = [];\n\n            for (let i = 0; i < polylinePoints.length - 1; i++) pointPairs.push([polylinePoints[i], polylinePoints[i + 1]]);\n\n            this.GraphicsThree3D.dxfGenerator.lineObjectsData.push({\n              id: lineData.id,\n              properties: lineData.properties.line,\n              pointPairs\n            });\n          }\n        });\n      });\n    }\n\n    addPointObjectsToDXF(pointData) {\n      let insertionPoints = pointData.insertionPoints;\n      let points = pointData.components.points;\n      points.forEach(point => {\n        if (point.objectType === 1 && point.objectGeneration.type === 1) {\n          insertionPoints.forEach(insertionPoint => {\n            let insertionVector = insertionPoint.rotationAngle ? this.utils.applyRotationToVector(insertionPoint.insertionVector, insertionPoint) : insertionPoint.insertionVector;\n            this.GraphicsThree3D.dxfGenerator.pointObjectsData.push({\n              id: pointData.id,\n              properties: pointData.properties.point,\n              position: this.utils.addVectorObjects(point.insertionPoint, insertionVector)\n            });\n          });\n        }\n      });\n    }\n\n    addToDimChainCollisionDetection(object, insertionPoints) {\n      insertionPoints.forEach(insertionPoint => {\n        let insertionVector = this.utils.initVector3(insertionPoint.insertionVector);\n        let newObject = object.clone();\n        let rotationAngle = insertionPoint.rotationAngle;\n        let pivotPoint = new this.THREE.Object3D();\n\n        if (rotationAngle) {\n          rotationAngle = rotationAngle * Math.PI / 180;\n          let rotationAxis = this.utils.initVector3(insertionPoint.rotationAxis);\n          pivotPoint.position.set(insertionPoint.rotationPoint.x, insertionPoint.rotationPoint.y, insertionPoint.rotationPoint.z);\n          pivotPoint.attach(newObject);\n          pivotPoint.rotateOnAxis(rotationAxis, rotationAngle);\n        } else pivotPoint.attach(newObject);\n\n        pivotPoint.position.add(insertionVector);\n        pivotPoint.updateMatrixWorld();\n        let baseObject = pivotPoint.children[0];\n        pivotPoint.children.forEach(child => child.applyMatrix4(pivotPoint.matrixWorld));\n        let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(baseObject);\n        this.GraphicsThree3D.DimensionalChainIntersectionDetection.meshArr.push(intersectionObjects);\n      });\n    }\n\n    addToPosAndNeg(mesh, objectData, positivesAndNegatives, type) {\n      if (objectData.objectType == 1) positivesAndNegatives[type].positiveObjects.push(mesh);else positivesAndNegatives[type].negativeObjects.push(mesh);\n    }\n\n    addPointsToWireframeRegions(points, wireframeRegions) {\n      points.forEach(pointsData => {\n        let offsetVector = pointsData.normal.clone().multiplyScalar(pointsData.distance);\n        let pointsArr = pointsData.pointsArrData;\n        let [eulerOne, eulerTwo] = this.utils.getEulerOneAndTwo(pointsData.normal);\n        let pointsPos = pointsArr.positives;\n        let pointsNeg = pointsArr.negatives;\n        let newRegionData = {\n          offsetVector,\n          eulerTwo,\n          positiveRegions: [],\n          negativeRegions: []\n        };\n        pointsPos.forEach(pointArr => {\n          let newRegion = {\n            regions: [[]],\n            inverted: false\n          };\n          pointArr.forEach(point => {\n            point.applyEuler(eulerOne);\n            newRegion.regions[0].push([point.x, point.y]);\n          });\n          newRegionData.positiveRegions.push(newRegion);\n        });\n        pointsNeg.forEach(pointArr => {\n          let newRegion = {\n            regions: [[]],\n            inverted: false\n          };\n          pointArr.forEach(point => {\n            point.applyEuler(eulerOne);\n            newRegion.regions[0].push([point.x, point.y]);\n          });\n          newRegionData.negativeRegions.push(newRegion);\n        });\n        wireframeRegions.push(newRegionData);\n      });\n    }\n\n  }\n\n  _exports.DrawingObjectLoader = DrawingObjectLoader;\n});","define(\"m08-2020/lib/FigureLoaders/DrawingPlaneLoader\", [\"exports\", \"m08-2020/lib/Utils\", \"m08-2020/lib/FigureLoaders/DimensionalChainLoader\", \"svg-parser\", \"three/examples/jsm/renderers/SVGRenderer.js\"], function (_exports, _Utils, _DimensionalChainLoader, _svgParser, _SVGRenderer) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.DrawingPlaneLoader = void 0;\n\n  class DrawingPlaneLoader {\n    constructor(GraphicsThree3D) {\n      this.THREE = GraphicsThree3D.THREE;\n      this.fontUrlArray = GraphicsThree3D.fontUrlArray;\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.utils = new _Utils.Utils(GraphicsThree3D.THREE);\n      this.lastPlaneID = \"\"; ///\n\n      this.loadDrawingPlanes = this.loadDrawingPlanes.bind(this);\n    }\n\n    loadDrawingPlanes() {\n      let jsonData = this.GraphicsThree3D.jsonData;\n      let settingProps = jsonData.settings.drawingPlane.properties;\n      let unitsData = jsonData.units;\n      let drawingPlanes = jsonData.drawingPlanes;\n      let units = this.utils.processUnits(unitsData);\n      let dimensionalChainLoader = new _DimensionalChainLoader.DimensionalChainLoader(this.GraphicsThree3D);\n      let dimensionalChains = jsonData.dimensionalChains;\n      this.lastPlaneID = drawingPlanes[drawingPlanes.length - 1][\"id\"];\n      let initCamParams = this.getInitialCameraParameters();\n      drawingPlanes.forEach(drawingPlane => {\n        let [cameraZoom, canvasWidth, canvasHeight] = this.getGraphicsParameters(this.GraphicsThree3D); // Components\n\n        let drawingData = drawingPlane.components.drawing;\n        let frameData = drawingPlane.components.frame;\n        let freeTexts = drawingPlane.components.freeTexts;\n        let scaleBarData = drawingPlane.components.scaleBar;\n        let scaleTextBlockData = drawingPlane.components.scaleTextBlock;\n        let unitTextBlockData = drawingPlane.components.unitTextBlock; // Properties\n\n        let properties = drawingPlane.properties;\n        let drawingProps = properties.drawing ? properties.drawing : settingProps.drawing;\n        let frameProps = properties.frame ? properties.frame : settingProps.frame;\n        let freeTextProps = properties.freeText ? properties.freeText : settingProps.freeText;\n        let scaleBarProps = properties.scaleBar ? properties.scaleBar : settingProps.scaleBar;\n        let scaleTextBlockProps = properties.scaleTextBlock ? properties.scaleTextBlock : settingProps.scaleTextBlock;\n        let unitTextBlockProps = properties.unitTextBlock ? properties.unitTextBlock : settingProps.unitTextBlock; ///\n\n        frameData = { ...frameData,\n          drawingNormal: drawingData.normalVector,\n          drawingVerticalVector: drawingData.verticalVector\n        };\n\n        if (drawingData && drawingProps) {\n          this.removeDimChains3D();\n          this.drawDimensionalChains(dimensionalChainLoader, dimensionalChains, drawingData);\n          this.checkWrongScale(frameData);\n          this.makeDrawing(drawingData, drawingProps);\n\n          if (frameData && frameProps) {\n            let frame = this.makeFrame(frameData, frameProps, drawingData);\n            if (freeTextProps && frameData) this.drawFreeTexts(freeTexts, freeTextProps, frameData, frame);\n            if (scaleTextBlockData && scaleTextBlockProps) this.drawScaleTextBlock(scaleTextBlockData, scaleTextBlockProps, frameData, frame);\n            if (unitTextBlockData && unitTextBlockProps) this.drawUnitTextBlock(unitTextBlockData, unitTextBlockProps, units, frameData, frame);\n            if (scaleBarData && scaleBarProps) this.generateScaleBarObject(scaleBarData, scaleBarProps, units.length, frameData, frame);\n          }\n        }\n\n        this.scaleCanvas(frameData, frameProps, this.GraphicsThree3D);\n        let initialWireframeStatus = this.makeObjectFilled(this.GraphicsThree3D);\n        let scale = this.getScale(frameData);\n        let drawingComponents = {\n          frameDataAndProps: {\n            frameData,\n            frameProps\n          },\n          freeTextDataAndProps: {\n            freeTexts,\n            freeTextProps\n          },\n          scaleTextBlockDataAndProps: {\n            scaleTextBlockData,\n            scaleTextBlockProps\n          },\n          unitTextBlockDataAndProps: {\n            unitTextBlockData,\n            unitTextBlockProps\n          },\n          scaleBarDataAndProps: {\n            scaleBarData,\n            scaleBarProps\n          }\n        };\n        let dxfPlaneData = this.getDXFPlaneData(drawingPlane, drawingProps, scale, drawingComponents, units);\n        this.downloadPNGandDXFAndReset(cameraZoom, canvasWidth, canvasHeight, dxfPlaneData);\n        this.resetToInitialWireframeStatus(this.GraphicsThree3D, initialWireframeStatus);\n      });\n      this.resetInitialCameraParameters(initCamParams);\n    }\n\n    resetInitialCameraParameters(initialParameters) {\n      let camera = this.GraphicsThree3D.camera;\n      let controls = this.GraphicsThree3D.controls;\n      let {\n        camZoom,\n        camPos,\n        camTarget\n      } = initialParameters;\n      camera.position.copy(camPos);\n      camera.lookAt(camTarget);\n      camera.updateProjectionMatrix();\n      controls.update();\n      camera.zoom = camZoom;\n      controls.target.copy(camTarget);\n      camera.up = new this.THREE.Vector3(0, 1, 0);\n      camera.lookAt(controls.target);\n      controls.update();\n    }\n\n    getInitialCameraParameters() {\n      return {\n        camZoom: this.GraphicsThree3D.camera.zoom,\n        camPos: this.GraphicsThree3D.camera.position.clone(),\n        camTarget: this.GraphicsThree3D.controls.target.clone()\n      };\n    }\n\n    getDXFPlaneData(drawingPlane, drawingProps, scale, drawingComponents, units) {\n      return {\n        id: drawingPlane.id,\n        output: drawingPlane.output,\n        normal: drawingPlane.components.drawing.normalVector,\n        scale,\n        units,\n        drawingComponents,\n        visualisation: {\n          drawingObject: drawingProps.visualisation.drawingObject,\n          fastener: drawingProps.visualisation.fastener,\n          arrow: drawingProps.visualisation.arrow\n        },\n        dxfFastenerVisualisation: { ...drawingProps.dxfFastenerVisualisation\n        }\n      };\n    }\n\n    checkWrongScale(frameData) {\n      let scaleType = frameData.scaleType;\n      if (scaleType < 1 || scaleType > 2) this.GraphicsThree3D.clearScene();else {\n        let testScale = this.getScaleToFitScene(frameData, this.GraphicsThree3D);\n        let checkScale = this.getScale(frameData);\n        if (checkScale < testScale) this.GraphicsThree3D.clearScene();\n      }\n    }\n    /**\n     * Download PNG\n     */\n\n\n    downloadPNGandDXFAndReset(cameraZoom, canvasWidth, canvasHeight, drawingPlaneData) {\n      let drawingOutput = drawingPlaneData.output;\n      this.GraphicsThree3D.renderAllScenes(this.GraphicsThree3D);\n\n      if (drawingOutput.dxf) {\n        if (drawingPlaneData.id === this.lastPlaneID) this.GraphicsThree3D.dxfGenerator.downloadDXF2D(\"plane.dxf\", drawingPlaneData);else this.GraphicsThree3D.dxfGenerator.generateBlockAndEntitySections(drawingPlaneData);\n      }\n\n      if (drawingOutput.image) this.GraphicsThree3D.downloadAsPNGImage(\"plane.png\");\n      this.GraphicsThree3D.clearScene();\n      this.GraphicsThree3D.camera.zoom = cameraZoom;\n      this.GraphicsThree3D.renderer.domElement.style.width = canvasWidth.toFixed(0) + \"px\";\n      this.GraphicsThree3D.renderer.domElement.style.height = canvasHeight.toFixed(0) + \"px\";\n      this.GraphicsThree3D.updateRendererAndCamera(this.GraphicsThree3D.renderer, this.GraphicsThree3D.camera);\n      this.GraphicsThree3D.renderAllScenes(this.GraphicsThree3D);\n      this.GraphicsThree3D.camera.up = new this.THREE.Vector3(0, 1, 0);\n      this.GraphicsThree3D.drawCustom(this.GraphicsThree3D.globalJSONData);\n    }\n\n    makeObjectFilled(GraphicsThree3D) {\n      let wireframeStatus = GraphicsThree3D.isWireFrameOnly;\n      GraphicsThree3D.isWireFrameOnly = true;\n      GraphicsThree3D.ToggleWireframe();\n      return wireframeStatus;\n    }\n\n    resetToInitialWireframeStatus(GraphicsThree3D, wireframeStatus) {\n      GraphicsThree3D.isWireFrameOnly = !wireframeStatus;\n      GraphicsThree3D.ToggleWireframe();\n    }\n\n    getGraphicsParameters(GraphicsThree3D) {\n      let cameraZoom = GraphicsThree3D.camera.zoom;\n      let rendererSize = GraphicsThree3D.renderer.getSize(new this.THREE.Vector2());\n      return [cameraZoom, rendererSize.x, rendererSize.y];\n    }\n    /**\n     * Scale Canvas\n     */\n\n\n    scaleCanvas(frameData, frameProps, GraphicsThree3D) {\n      let [frameWidth, frameRatio] = this.getCameraWidthAndRatio(frameData, frameProps);\n      this.changeRendererSize(frameRatio, GraphicsThree3D);\n      this.zoomCamera(GraphicsThree3D.camera, frameRatio, frameWidth);\n    }\n\n    getCameraWidthAndRatio(frameData, frameProps) {\n      let lineWidth = frameProps.outerLine.thickness;\n      let frameWidth = frameData.width + lineWidth;\n      let frameHeight = frameData.height + lineWidth;\n      let scale = this.getScale(frameData);\n      let scaledWidth = frameWidth * scale;\n      let frameRatio = frameWidth / frameHeight;\n      return [scaledWidth, frameRatio];\n    }\n\n    changeRendererSize(frameRatio, GraphicsThree3D) {\n      const IMG_WIDTH = 2000;\n      let canvasSize = GraphicsThree3D.renderer.getSize(new this.THREE.Vector2());\n      let canvasWidth = canvasSize.x;\n      let canvasHeight = canvasSize.y;\n      let canvasRatio = canvasWidth / canvasHeight;\n      const QUALITY_SCALE = IMG_WIDTH / canvasWidth;\n      GraphicsThree3D.renderer.setSize(QUALITY_SCALE * canvasWidth * frameRatio / canvasRatio, QUALITY_SCALE * canvasHeight);\n    }\n\n    zoomCamera(camera, frameRatio, frameWidth) {\n      const MULTIPLIER = 16;\n      const CAMERA_VIEW_SIZE = 1000;\n      camera.left = -CAMERA_VIEW_SIZE * frameRatio / MULTIPLIER;\n      camera.right = CAMERA_VIEW_SIZE * frameRatio / MULTIPLIER;\n      camera.top = CAMERA_VIEW_SIZE / MULTIPLIER;\n      camera.bottom = -CAMERA_VIEW_SIZE / MULTIPLIER;\n      let cameraWidth = camera.right - camera.left;\n      camera.zoom = cameraWidth / frameWidth;\n      camera.updateProjectionMatrix();\n    }\n\n    drawDimensionalChains(dimensionalChainLoader, dimensionalChains, drawingData) {\n      let drawingNormal = this.utils.initVector3(drawingData.normalVector).normalize();\n      let drawingVerticalVec = this.utils.initVector3(drawingData.verticalVector).normalize();\n      let drawingHorizontalVec = new this.THREE.Vector3().crossVectors(drawingNormal, drawingVerticalVec).normalize();\n      let clippingPlane;\n\n      if (drawingData.type === 2) {\n        let planeDistance = this.getClippingPlaneDistance(drawingData, drawingNormal);\n        clippingPlane = new this.THREE.Plane(drawingNormal, planeDistance);\n      }\n\n      if (dimensionalChains) dimensionalChains.forEach(chain => {\n        let view2dAlignments = chain.alignments.views2d; ///\n\n        if (view2dAlignments) {\n          view2dAlignments.forEach(alignment => {\n            if (chain.alignments.textAlignment === 1) {\n              let pointsDir = this.getTextDirectionVec({\n                drawingVerticalVec,\n                drawingHorizontalVec\n              }, chain.referencePoints);\n              alignment.normalVector = drawingNormal.clone().negate();\n              alignment.directionVector = pointsDir;\n            }\n          }); ///\n\n          let chainData = { ...chain\n          };\n          chainData.alignments = { ...chain.alignments\n          };\n          chainData.alignments.textAlignment = 2;\n          view2dAlignments.forEach(alignment => {\n            let normalVector = new this.THREE.Vector3().crossVectors(alignment.offsetVector, alignment.directionVector).normalize();\n            let dotProdAbs = Math.abs(normalVector.dot(drawingNormal));\n\n            if (dotProdAbs === 1) {\n              let chains = dimensionalChainLoader.drawMaskette(chainData, alignment);\n              chains.forEach(ch => {\n                if (drawingData.type === 1 || drawingData.type === 2 && this.chainOnPlane(ch, clippingPlane)) this.GraphicsThree3D.scene.add(ch);\n              });\n            }\n          });\n        }\n      });\n      this.GraphicsThree3D.centerScene();\n      this.GraphicsThree3D.DimensionalChainIntersectionDetection.chainArr = [];\n    }\n\n    getTextDirectionVec(drawingSpaceVectors, chainReferencePoints) {\n      let {\n        drawingVerticalVec,\n        drawingHorizontalVec\n      } = drawingSpaceVectors;\n      let startPoint = this.utils.initVector3(chainReferencePoints[0]);\n      let endPoint = this.utils.initVector3(chainReferencePoints[chainReferencePoints.length - 1]);\n      let pointsDir = new this.THREE.Vector3().subVectors(endPoint, startPoint).normalize();\n      let yDot = drawingVerticalVec.dot(pointsDir);\n\n      if (Math.abs(yDot) === 1) {\n        if (yDot < 0) pointsDir.negate();\n      } else {\n        let xDot = drawingHorizontalVec.dot(pointsDir);\n        if (xDot < 0) pointsDir.negate();\n      }\n\n      return pointsDir;\n    }\n\n    removeDimChains3D() {\n      this.GraphicsThree3D.visualisationControlObjects.dimensionalChain.forEach(chain => this.GraphicsThree3D.scene.remove(chain));\n      this.GraphicsThree3D.visualisationControlObjects.dimensionalChain = [];\n    }\n\n    chainOnPlane(chain, plane) {\n      let isOnPlane = true;\n      chain.traverse(child => {\n        if (plane.distanceToPoint(child.position) !== 0) isOnPlane = false;\n      });\n      return isOnPlane;\n    }\n    /**\n     * ScaleBar\n     */\n\n\n    generateScaleBarObject(scaleBarData, scaleBarProps, unitsLength, frameData, frame) {\n      let areaProps = scaleBarProps.area;\n      let lineProps = scaleBarProps.line;\n      let textProps = scaleBarProps.text;\n      let normalVector = new this.THREE.Vector3(0, 0, 1);\n      let directionVector = this.utils.initVector3(scaleBarData.directionVector).normalize();\n      let insertionPoint = this.utils.initVector3(scaleBarData.insertionPoint);\n      let [outerPoints, _] = this.getFramePoints(frameData);\n      insertionPoint.add(outerPoints[0]);\n      let scale = this.getScale(frameData);\n      let scaleBarSize = {\n        height: scaleBarData.height,\n        segmentWidth: 1\n      };\n      let scaleBarObject = new this.THREE.Object3D();\n      let scaleBarLine = this.drawScaleBarLine(scaleBarSize, lineProps);\n      scaleBarObject.add(scaleBarLine);\n      let scaleBarArea = this.drawScaleBarAreas(scaleBarSize, areaProps);\n      scaleBarObject.add(scaleBarArea);\n      this.drawScaleBarTexts(scaleBarData, scale, unitsLength, textProps, scaleBarObject);\n      scaleBarObject = this.alignScaleBar(scaleBarObject, scaleBarData);\n      this.utils.alignObjectWithVectors(scaleBarObject, normalVector, directionVector);\n      scaleBarObject.position.add(insertionPoint);\n      frame.add(scaleBarObject);\n    }\n\n    alignScaleBar(scaleBarObject, scaleBarData) {\n      let relativePosition = scaleBarData.relativePosition;\n      let alignedScaleBar = new this.THREE.Object3D();\n      alignedScaleBar.add(scaleBarObject);\n      let bbox = new this.THREE.Box3().setFromObject(scaleBarObject);\n      this.GraphicsThree3D.dxfGenerator.drawingScaleBarBBox = bbox.clone();\n      let bboxSize = bbox.getSize(new this.THREE.Vector3());\n      let centerOffset = bbox.getCenter(new this.THREE.Vector3());\n      scaleBarObject.children.forEach(child => child.position.sub(centerOffset));\n      let alignmentOffset = this.getScaleBarAlignmentOffset(bboxSize, relativePosition);\n      scaleBarObject.position.add(alignmentOffset);\n      return alignedScaleBar;\n    }\n\n    getScaleBarAlignmentOffset(bboxSize, relativePosition) {\n      let alignmentOffset = new this.THREE.Vector3(0, 0, 0);\n\n      switch (relativePosition) {\n        case 2:\n          alignmentOffset.set(bboxSize.x / 2, bboxSize.y / 2, 0);\n          break;\n\n        case 3:\n          alignmentOffset.set(bboxSize.x / 2, -bboxSize.y / 2, 0);\n          break;\n\n        case 4:\n          alignmentOffset.set(-bboxSize.x / 2, -bboxSize.y / 2, 0);\n          break;\n\n        case 5:\n          alignmentOffset.set(-bboxSize.x / 2, bboxSize.y / 2, 0);\n          break;\n\n        default:\n          break;\n      }\n\n      return alignmentOffset;\n    }\n\n    drawScaleBarTexts(scaleBarData, scale, unitsLength, textProps, scaleBarObject) {\n      const NUM_OF_SEGMENTS = 5;\n      const SEGMENT_WIDTH = 1;\n      const TEXT_RELATIVE_POSITION = 1;\n      let decimalPlaces = scaleBarData.decimalPlaces;\n      let distance = scaleBarData.distance;\n      let height = scaleBarData.height;\n      let textOffset = scaleBarData.textOffset;\n      let scaleFactor = this.getScaleFactor(unitsLength);\n      let heightOffset = -distance - textProps.size / 2;\n      let textData = {\n        content: \"\",\n        normalVector: {\n          x: 0,\n          y: 0,\n          z: 1\n        },\n        directionVector: {\n          x: 1,\n          y: 0,\n          z: 0\n        },\n        insertionPoint: {\n          x: 0,\n          y: heightOffset,\n          z: 0\n        },\n        relativePosition: TEXT_RELATIVE_POSITION\n      };\n\n      for (let i = 0; i <= NUM_OF_SEGMENTS; i++) {\n        textData.content = (i * scale * scaleFactor).toFixed(decimalPlaces);\n        if (i === 5 && unitsLength) textData.content += ` ${unitsLength}`;\n\n        if (textOffset) {\n          if (i % 2 === 1) textData.insertionPoint.y = height - heightOffset;else textData.insertionPoint.y = heightOffset;\n        }\n\n        textData.insertionPoint.x = i * SEGMENT_WIDTH;\n        let font = this.GraphicsThree3D.loadFont(textProps);\n        let text = this.GraphicsThree3D.drawText(textData, textProps, font);\n        scaleBarObject.add(text);\n      }\n    }\n\n    getScaleFactor(unit) {\n      let factor = 1;\n\n      switch (unit) {\n        case \"mm\":\n          factor *= 10;\n          break;\n\n        case \"m\":\n          factor /= 100;\n          break;\n\n        case \"km\":\n          factor /= 100000;\n          break;\n\n        default:\n          break;\n      }\n\n      return factor;\n    }\n\n    drawScaleBarAreas(scaleBarSize, areaProps) {\n      const NUM_OF_SEGMENTS = 5;\n      let height = scaleBarSize.height;\n      let segmentWidth = scaleBarSize.segmentWidth;\n      let totalWidth = NUM_OF_SEGMENTS * segmentWidth;\n      let geoOne = new this.THREE.PlaneGeometry(segmentWidth, height);\n      let geoTwo = geoOne.clone();\n      geoOne.translate(-segmentWidth, 0, 0);\n      geoTwo.translate(segmentWidth, 0, 0);\n      geoOne.merge(geoTwo);\n      geoOne.translate(totalWidth / 2, height / 2, 0);\n      let mat = this.utils.getMaterialFromColorProps(areaProps.color);\n      let area = new this.THREE.Mesh(geoOne, mat);\n      return area;\n    }\n\n    drawScaleBarLine(scaleBarSize, lineProps) {\n      const NUM_OF_SEGMENTS = 5;\n      let height = scaleBarSize.height;\n      let segmentWidth = scaleBarSize.segmentWidth;\n      let totalWidth = NUM_OF_SEGMENTS * segmentWidth;\n      let pts = [new this.THREE.Vector3(0, 0, 0), new this.THREE.Vector3(totalWidth, 0, 0), new this.THREE.Vector3(totalWidth, height), new this.THREE.Vector3(0, height, 0)];\n      let line = this.drawOutline(pts, lineProps, true);\n      this.addPointsToVertices(lineProps.thickness, lineProps.color, pts, line);\n      return line;\n    }\n    /**\n     * UnitTextBlock\n     */\n\n\n    drawUnitTextBlock(unitTextBlockData, unitTextBlockProps, units, frameData, frame) {\n      let font = this.GraphicsThree3D.loadFont(unitTextBlockProps);\n      let [outerPoints, _] = this.getFramePoints(frameData);\n      let zeroPoint = outerPoints[0];\n      let content = this.generateUnitTextContent(unitTextBlockData, units);\n      let data = this.generateTextData(content, unitTextBlockData, zeroPoint);\n      let text = this.GraphicsThree3D.drawText(data, unitTextBlockProps, font);\n      frame.add(text);\n    }\n\n    generateUnitTextContent(unitTextBlockData, units) {\n      let content = \"\";\n      let startText = unitTextBlockData.startText;\n      let endText = unitTextBlockData.endText;\n      let separator = unitTextBlockData.separator;\n      content += startText;\n      let unitValues = Object.values(units);\n      unitValues.forEach((value, index) => {\n        if (index && value) content += separator;\n        if (value) content += value;\n      });\n      content += endText;\n      return content;\n    }\n    /**\n     * ScaleTextBlock\n     */\n\n\n    drawScaleTextBlock(scaleTextBlockData, scaleTextBlockProps, frameData, frame) {\n      let font = this.GraphicsThree3D.loadFont(scaleTextBlockProps);\n      let [outerPoints, _] = this.getFramePoints(frameData);\n      let zeroPoint = outerPoints[0];\n      let decimals = scaleTextBlockData.decimalPlaces;\n      let scale = this.getScale(frameData);\n      let content = `${scaleTextBlockData.text} ${scale.toFixed(decimals)}`;\n      let data = this.generateTextData(content, scaleTextBlockData, zeroPoint);\n      let text = this.GraphicsThree3D.drawText(data, scaleTextBlockProps, font);\n      frame.add(text);\n    }\n    /**\n     * FreeTexts\n     */\n\n\n    drawFreeTexts(freeTexts, textProps, frameData, frame) {\n      let font = this.GraphicsThree3D.loadFont(textProps);\n      let [outerPoints, _] = this.getFramePoints(frameData);\n      let zeroPoint = outerPoints[0];\n      freeTexts.forEach(textData => {\n        let content = textData.content;\n        let data = this.generateTextData(content, textData, zeroPoint);\n        let text = this.GraphicsThree3D.drawText(data, textProps, font);\n        frame.add(text);\n      });\n    }\n\n    generateTextData(content, textData, zeroPoint) {\n      let id = textData.id;\n      let relativePosition = textData.relativePosition;\n      let directionVector = this.utils.initVector3(textData.directionVector).normalize();\n      let insertionPoint = this.utils.initVector3(textData.insertionPoint);\n      insertionPoint.add(zeroPoint);\n      let data = {\n        content,\n        id,\n        relativePosition,\n        directionVector: {\n          x: directionVector.x,\n          y: directionVector.y,\n          z: directionVector.z\n        },\n        normalVector: {\n          x: 0,\n          y: 0,\n          z: 1\n        },\n        insertionPoint: {\n          x: insertionPoint.x,\n          y: insertionPoint.y,\n          z: insertionPoint.z\n        }\n      };\n      return data;\n    }\n    /**\n     * Frame\n     */\n\n\n    makeFrame(frameData, frameProps, drawingData) {\n      let normalVector = this.utils.initVector3(drawingData.normalVector).normalize().negate();\n      let verticalVector = this.utils.initVector3(drawingData.verticalVector).normalize().negate();\n      let frame = this.generateFrameObject(frameData, frameProps);\n      this.scaleFrame(frame, frameData);\n      this.utils.alignObjectWithVectors(frame, normalVector, new this.THREE.Vector3().crossVectors(normalVector, verticalVector));\n      frame.position.copy(this.getFramePosition(drawingData, this.GraphicsThree3D));\n      this.GraphicsThree3D.scene.add(frame);\n      return frame;\n    }\n\n    getScaleToFitScene(frameData, GraphicsThree3D) {\n      let normalVec = this.utils.initVector3(frameData.drawingNormal);\n      let upVec = this.utils.initVector3(frameData.drawingVerticalVector);\n      let crossVec = new this.THREE.Vector3().crossVectors(normalVec, upVec);\n      let bboxPoints = [new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMinZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMinZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMinZ), new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMinZ)];\n      let projectedPoints = this.projectPointsOnPlane(bboxPoints, normalVec);\n      let [verticalPoints, horizontalPoints] = this.getVerticalAndHorizontalPoints(projectedPoints, upVec, crossVec);\n      let [maxWidth, maxHeight] = this.getMaxWidthHeightProjected(verticalPoints, horizontalPoints, upVec, crossVec);\n      let frameWidth = frameData.width - frameData.border.left - frameData.border.right;\n      let frameHeight = frameData.height - frameData.border.top - frameData.border.bottom; // let scale;\n      // if (frameWidth < frameHeight) scale = maxWidth / frameWidth;\n      // else scale = maxHeight / frameHeight;\n      // let scale = maxWidth / frameWidth;\n\n      let scale = Math.max(maxWidth / frameWidth, maxHeight / frameHeight);\n      return scale;\n    }\n\n    getMaxWidthHeightProjected(verticalPoints, horizontalPoints, upVec, crossVec) {\n      let maxHeight = 0;\n      let maxWidth = 0;\n      const EPSILON = 0.0001;\n      verticalPoints.up.forEach(upPoint => verticalPoints.down.forEach(downPoint => {\n        let distance = upPoint.distanceTo(downPoint);\n        let dirVec = downPoint.clone().sub(upPoint).normalize();\n        if (distance > maxHeight && Math.abs(dirVec.dot(upVec)) > 1 - EPSILON) maxHeight = distance;\n      }));\n      horizontalPoints.right.forEach(rightPoint => horizontalPoints.left.forEach(leftPoint => {\n        let distance = rightPoint.distanceTo(leftPoint);\n        let dirVec = rightPoint.clone().sub(leftPoint).normalize();\n        if (distance > maxWidth && Math.abs(dirVec.dot(crossVec)) > 1 - EPSILON) maxWidth = distance;\n      }));\n      return [maxWidth, maxHeight];\n    }\n\n    projectPointsOnPlane(pointsArr, normalVec) {\n      let projectedPoints = [];\n      pointsArr.forEach(point => {\n        projectedPoints.push(point.projectOnPlane(normalVec));\n      });\n      return projectedPoints;\n    }\n\n    getVerticalAndHorizontalPoints(pointsArr, upVec, crossVec) {\n      let verticalPoints = {\n        up: [],\n        down: []\n      };\n      let horizontalPoints = {\n        right: [],\n        left: []\n      };\n      pointsArr.forEach(point => {\n        if (point.dot(upVec) > 0) verticalPoints.up.push(point);else verticalPoints.down.push(point);\n        if (point.dot(crossVec) > 0) horizontalPoints.right.push(point);else horizontalPoints.left.push(point);\n      });\n      return [verticalPoints, horizontalPoints];\n    }\n\n    getScale(frameData) {\n      let scaleType = frameData.scaleType;\n      let scale = 1;\n\n      if (scaleType === 1) {\n        scale = this.getScaleToFitScene(frameData, this.GraphicsThree3D);\n      } else if (scaleType === 2) {\n        let scaleList = frameData.scaleList;\n        let minimumScale = this.getScaleToFitScene(frameData, this.GraphicsThree3D);\n        let maximumZoom = Infinity;\n        scaleList.forEach(scaleStr => {\n          let scaleParams = scaleStr.split(\":\");\n          let newScale = parseFloat(scaleParams[1]) / parseFloat(scaleParams[0]);\n\n          if (newScale >= minimumScale && scale < maximumZoom) {\n            scale = newScale;\n            maximumZoom = scale;\n          }\n        });\n      }\n\n      return scale;\n    }\n\n    scaleFrame(frame, frameData) {\n      let scale = this.getScale(frameData);\n      frame.scale.set(scale, scale, scale);\n    }\n\n    getFramePosition(drawingData, GraphicsThree3D) {\n      let normalVector = this.utils.initVector3(drawingData.normalVector).normalize();\n      let framePos;\n\n      if (drawingData.positionVector) {\n        let positionVec = this.utils.initVector3(drawingData.positionVector);\n        let objMidVec = GraphicsThree3D.objectMidVector.clone();\n        let posDir = positionVec.clone().normalize();\n        let posDist = positionVec.length();\n        let proj = objMidVec.dot(posDir);\n\n        if (proj > posDist) {\n          let delta = proj - posDist;\n          let proportion = delta / proj;\n          framePos = objMidVec.sub(normalVector.clone().multiplyScalar(proportion));\n        } else {\n          let positionDirection = positionVec.clone().normalize();\n          let planeDistance = positionVec.length();\n          if (normalVector.dot(positionDirection) > 0) planeDistance *= -1;\n          let viewPlane = new this.THREE.Plane(normalVector, planeDistance);\n          let projectedPoint = new this.THREE.Vector3();\n          viewPlane.projectPoint(objMidVec, projectedPoint);\n          framePos = projectedPoint;\n        }\n      } else {\n        let midVec = GraphicsThree3D.objectMidVector.clone();\n        let bboxPoints = [new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMaxZ), new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMinZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMinY, GraphicsThree3D.objectMinZ), new this.THREE.Vector3(GraphicsThree3D.objectMaxX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMinZ), new this.THREE.Vector3(GraphicsThree3D.objectMinX, GraphicsThree3D.objectMaxY, GraphicsThree3D.objectMinZ)].map(point => point.sub(midVec));\n        let viewPlane = new this.THREE.Plane(normalVector);\n        let minDistance = 0;\n        bboxPoints.forEach(point => {\n          let distance = viewPlane.distanceToPoint(point);\n          if (distance < minDistance) minDistance = distance;\n        });\n        framePos = midVec.add(normalVector.clone().multiplyScalar(minDistance));\n      }\n\n      return framePos;\n    }\n\n    generateFrameObject(frameData, frameProps) {\n      let innerLineProps = frameProps.innerLine;\n      let outerLineProps = frameProps.outerLine;\n      let areaProps = frameProps.area;\n      let [outerPoints, innerPoints] = this.getFramePoints(frameData);\n      let frameObject = new this.THREE.Object3D();\n      let plane = this.drawPlane(frameData, areaProps);\n      frameObject.add(plane);\n      let outerLine = this.drawOutline(outerPoints, outerLineProps, true);\n      frameObject.add(outerLine);\n      let innerLine = this.drawOutline(innerPoints, innerLineProps, true);\n      frameObject.add(innerLine);\n      this.drawFrameVertexPoints(outerPoints, innerPoints, frameProps, frameObject);\n      return frameObject;\n    }\n\n    drawOutline(points, lineProps) {\n      let firstLine = new this.THREE.Mesh();\n\n      if (lineProps.thickness && lineProps.color.alpha && (lineProps.type || lineProps.type === undefined)) {\n        if (lineProps.type === 1 || lineProps.type === undefined || lineProps.factor === 0 && lineProps.type !== null && lineProps.type !== 0) {\n          let lineMeshArray = [];\n\n          for (let i = 0; i < points.length - 1; i++) {\n            if (points[i].distanceTo(points[i + 1]) > 0) {\n              let lineMesh = this.utils.drawLine(points[i], points[i + 1], lineProps, true);\n              lineMeshArray.push(lineMesh);\n            }\n          }\n\n          if (points[points.length - 1].distanceTo(points[0]) > 0) {\n            let lineMesh = this.utils.drawLine(points[points.length - 1], points[0], lineProps, true);\n            lineMeshArray.push(lineMesh);\n          }\n\n          firstLine = lineMeshArray.length > 0 ? lineMeshArray.splice(0, 1)[0] : new this.THREE.Mesh();\n          let lineMaterial = firstLine.material;\n          firstLine.updateMatrixWorld();\n          firstLine.geometry.applyMatrix4(firstLine.matrixWorld);\n\n          for (let i = 0; i < lineMeshArray.length; i++) {\n            lineMeshArray[i].updateMatrixWorld();\n            lineMeshArray[i].geometry.applyMatrix4(lineMeshArray[i].matrixWorld);\n            firstLine.geometry.merge(lineMeshArray[i].geometry);\n          }\n\n          firstLine = new this.THREE.Mesh(firstLine.geometry, lineMaterial);\n        }\n      }\n\n      return firstLine;\n    }\n\n    getFramePoints(frameData) {\n      let width = frameData.width;\n      let height = frameData.height;\n      let borderLeft = frameData.border.left;\n      let borderRight = frameData.border.right;\n      let borderTop = frameData.border.top;\n      let borderBot = frameData.border.bottom;\n      let outerPoints = [new this.THREE.Vector3(-width / 2, -height / 2, 0), new this.THREE.Vector3(width / 2, -height / 2, 0), new this.THREE.Vector3(width / 2, height / 2, 0), new this.THREE.Vector3(-width / 2, height / 2, 0)];\n      let innerPoints = [new this.THREE.Vector3(-width / 2 + borderLeft, -height / 2 + borderBot, 0), new this.THREE.Vector3(width / 2 - borderRight, -height / 2 + borderBot, 0), new this.THREE.Vector3(width / 2 - borderRight, height / 2 - borderTop, 0), new this.THREE.Vector3(-width / 2 + borderLeft, height / 2 - borderTop, 0)];\n      return [outerPoints, innerPoints];\n    }\n\n    drawFrameVertexPoints(outerPoints, innerPoints, frameProps, frameObject) {\n      let outerColor = frameProps.outerLine.color;\n      let innerColor = frameProps.innerLine.color;\n      let outerSize = frameProps.outerLine.thickness;\n      let innerSize = frameProps.innerLine.thickness;\n      if (outerSize) this.addPointsToVertices(outerSize, outerColor, outerPoints, frameObject);\n      if (innerSize) this.addPointsToVertices(innerSize, innerColor, innerPoints, frameObject);\n    }\n\n    addPointsToVertices(size, color, points, frameObject) {\n      let material = this.utils.getMaterialFromColorProps(color);\n      points.forEach(point => {\n        let mesh = this.drawPoint(point, size, material);\n        frameObject.add(mesh);\n      });\n    }\n\n    drawPoint(position, size, material) {\n      let geometry = new this.THREE.BoxBufferGeometry(size, size, size);\n      let mesh = new this.THREE.Mesh(geometry, material);\n      mesh.position.copy(position);\n      return mesh;\n    }\n\n    drawPlane(frameData, areaProps) {\n      let width = frameData.width;\n      let height = frameData.height;\n      let planeWidth = width;\n      let planeHeight = height;\n      let planeGeo = new this.THREE.PlaneBufferGeometry(planeWidth, planeHeight);\n      let planeMat = this.utils.getMaterialFromColorProps(areaProps.color);\n      planeMat.depthWrite = false;\n      let plane = new this.THREE.Mesh(planeGeo, planeMat);\n      return plane;\n    }\n    /**\n     * Drawing\n     */\n\n\n    makeDrawing(drawingData, drawingProps) {\n      if (drawingData.type === 1 || drawingData.type === 2) {\n        let normalVector = this.utils.initVector3(drawingData.normalVector).normalize();\n        let verticalVector = this.utils.initVector3(drawingData.verticalVector).normalize();\n        let scene = this.GraphicsThree3D.scene;\n        this.positionCamera(normalVector.clone().negate(), verticalVector);\n\n        if (drawingData.type === 2) {\n          let planeDistance = this.getClippingPlaneDistance(drawingData, normalVector);\n          let clippingPlane = new this.THREE.Plane(normalVector, planeDistance);\n          this.clipSceneObjects(scene, clippingPlane);\n        }\n\n        this.changeObjectsTransparency(this.GraphicsThree3D.transparencyControlObjects, drawingProps.transparency);\n        this.changeObjectsVisualisation(this.GraphicsThree3D.visualisationControlObjects, drawingProps.visualisation);\n      }\n    }\n\n    positionCamera(normalVector, verticalVector) {\n      let camera = this.GraphicsThree3D.camera;\n      let midVector = this.GraphicsThree3D.objectMidVector.clone();\n      let cameraDistance = 150;\n      let cameraPos = normalVector.clone().multiplyScalar(cameraDistance).add(midVector);\n      let upGenObj = new this.THREE.Object3D();\n      let upVector = this.GraphicsThree3D.getMeshUpVector(upGenObj, normalVector.clone());\n      let sceneRotAngle = upVector.angleTo(verticalVector);\n      camera.position.set(0, 0, 0);\n      camera.lookAt(new this.THREE.Vector3(0, 0, 1));\n      camera.rotation.z = sceneRotAngle;\n      camera.up = verticalVector;\n      camera.position.copy(cameraPos);\n      camera.lookAt(midVector);\n      camera.zoom = 1;\n      camera.updateProjectionMatrix();\n    }\n\n    getClippingPlaneDistance(drawingData, normalVector) {\n      let positionVector = this.utils.initVector3(drawingData.positionVector);\n      let positionDirection = positionVector.clone().normalize();\n      let planeDistance = positionVector.length();\n      if (normalVector.dot(positionDirection) > 0) planeDistance *= -1;\n      return planeDistance;\n    }\n\n    changeObjectsTransparency(objects, transparencyProps) {\n      for (let [key, value] of Object.entries(objects)) {\n        value.forEach(mesh => {\n          let material = mesh.material;\n          let transparency = transparencyProps[key] / 255.0;\n          if (material.length) material.forEach(mat => mat.opacity = transparency);else material.opacity = transparency;\n        });\n      }\n    }\n\n    changeObjectsVisualisation(objects, visualisationProps) {\n      for (let [key, value] of Object.entries(objects)) {\n        value.forEach(object => {\n          let visualisation = visualisationProps[key];\n          object.visible = visualisation;\n        });\n      }\n    }\n\n    clipSceneObjects(scene, clippingPlane) {\n      let objectIDs = {};\n      scene.traverse(object => {\n        if (object.type === \"Mesh\" || object.type === \"LineLoop\") {\n          let material = object.material;\n          this.clipMaterial(material, clippingPlane);\n          if (!object.isDrawingObject) this.clipMaterialBack(material, clippingPlane);\n          if (object.type === \"Mesh\") this.cutMesh(object, objectIDs, clippingPlane);\n        }\n      });\n    }\n\n    clipMaterial(material, plane) {\n      if (material.length) material.forEach(mat => this.addClippingPlane(mat, plane));else this.addClippingPlane(material, plane);\n    }\n\n    addClippingPlane(material, plane) {\n      if (material.clippingPlanes) material.clippingPlanes.push(plane);else material.clippingPlanes = [plane];\n    }\n\n    clipMaterialBack(material, plane) {\n      const OFFSET = 1;\n      let backPlane = plane.clone();\n      backPlane.normal.negate();\n      backPlane.constant = -backPlane.constant + OFFSET;\n      material.clippingPlanes.push(backPlane);\n    }\n\n    cutMesh(mesh, ids, plane) {\n      if (mesh.isDrawingObject) {\n        const ERASER_OFFSET = 1;\n        let eraserSize = 500;\n\n        if (!(mesh.uuid in ids)) {\n          ids[mesh.uuid] = 1;\n          let eraserPos = plane.normal.clone().multiplyScalar(-plane.constant + eraserSize / 2 + ERASER_OFFSET);\n          let eraserMesh = this.utils.makeTestMesh(eraserPos, eraserSize);\n          eraserMesh.updateMatrix();\n          let meshCSG = this.GraphicsThree3D.CSG.fromMesh(mesh);\n          let eraserCSG = this.GraphicsThree3D.CSG.fromMesh(eraserMesh);\n          let subCSG = meshCSG.subtract(eraserCSG);\n          mesh.geometry = this.GraphicsThree3D.CSG.toMesh(subCSG, new this.THREE.Matrix4()).geometry;\n        }\n      }\n    }\n\n    getStencilMaterials() {\n      // PASS 1\n      // everywhere that the back faces are visible (clipped region) the stencil\n      // buffer is incremented by 1.\n      let backFaceStencilMat = new this.THREE.MeshBasicMaterial();\n      backFaceStencilMat.depthWrite = false;\n      backFaceStencilMat.depthTest = false;\n      backFaceStencilMat.colorWrite = false;\n      backFaceStencilMat.stencilWrite = true;\n      backFaceStencilMat.stencilFunc = this.THREE.AlwaysStencilFunc;\n      backFaceStencilMat.side = this.THREE.BackSide;\n      backFaceStencilMat.stencilFail = this.THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZFail = this.THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZPass = this.THREE.IncrementWrapStencilOp; // PASS 2\n      // everywhere that the front faces are visible the stencil\n      // buffer is decremented back to 0.\n\n      let frontFaceStencilMat = new this.THREE.MeshBasicMaterial();\n      frontFaceStencilMat.depthWrite = false;\n      frontFaceStencilMat.depthTest = false;\n      frontFaceStencilMat.colorWrite = false;\n      frontFaceStencilMat.stencilWrite = true;\n      frontFaceStencilMat.stencilFunc = this.THREE.AlwaysStencilFunc;\n      frontFaceStencilMat.side = this.THREE.FrontSide;\n      frontFaceStencilMat.stencilFail = this.THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZFail = this.THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZPass = this.THREE.DecrementWrapStencilOp; // PASS 3\n      // draw the plane everywhere that the stencil buffer != 0, which will\n      // only be in the clipped region where back faces are visible.\n\n      let planeStencilMat = new this.THREE.MeshNormalMaterial();\n      planeStencilMat.stencilWrite = true;\n      planeStencilMat.stencilRef = 0;\n      planeStencilMat.stencilFunc = this.THREE.NotEqualStencilFunc;\n      planeStencilMat.stencilFail = this.THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZFail = this.THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZPass = this.THREE.ReplaceStencilOp;\n      return [backFaceStencilMat, frontFaceStencilMat, planeStencilMat];\n    }\n\n  }\n\n  _exports.DrawingPlaneLoader = DrawingPlaneLoader;\n\n  function saveSVG(GraphicsThree3D) {\n    let rendererSize = GraphicsThree3D.renderer.getSize(new GraphicsThree3D.THREE.Vector2());\n    var rendererSVG = new _SVGRenderer.SVGRenderer();\n    rendererSVG.setSize(rendererSize.x, rendererSize.y);\n    rendererSVG.render(GraphicsThree3D.scene, GraphicsThree3D.camera);\n    console.log(rendererSVG.domElement);\n    var XMLS = new XMLSerializer();\n    var svgfile = XMLS.serializeToString(rendererSVG.domElement);\n    console.log(svgfile);\n    var svgData = svgfile;\n    var preface = '<?xml version=\"1.0\" standalone=\"no\"?>\\r\\n';\n    var svgBlob = new Blob([preface, svgData], {\n      type: \"image/svg+xml;charset=utf-8\"\n    });\n    var svgUrl = URL.createObjectURL(svgBlob);\n    var downloadLink = document.createElement(\"a\");\n    downloadLink.href = svgUrl;\n    downloadLink.download = \"drawing.svg\";\n    document.body.appendChild(downloadLink);\n    downloadLink.click();\n    document.body.removeChild(downloadLink); // let parsed = parse(svgfile);\n    // console.log(parsed)\n    // let data = \"text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(parsed))\n    // let link = document.createElement(\"a\");\n    // link.href = \"data: \" + data;\n    // link.download = \"svg_data.json\";\n    // link.click();\n    // let testMesh = this.utils.makeTestMesh(new this.THREE.Vector3(), 10);\n    // let exporter = new STLExporter();\n    // let stlData = exporter.parse(testMesh, { binary: true });\n    // console.log(stlData)\n    // // let link = document.createElement(\"a\");\n    // // link.style.display = \"none\";\n    // // document.body.appendChild(link);\n    // let blob = new Blob( [stlData], {type: \"application/octet-stream\"} );\n    // // link.href = URL.createObjectURL(blob);\n    // // link.download = \"testBox.stl\";\n    // // link.click();\n    // let deserializedStl = jscadIO.deserializers.stl(stlData, blob, {\n    //   output: \"csg\"\n    // });\n    // let dxfStringArray = jscadIO.dxfSerializer.serialize(deserializedStl);\n    // console.log(dxfStringArray)\n  }\n});","define(\"m08-2020/lib/FigureLoaders/FastenerLoader\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.FastenerLoader = void 0;\n\n  class FastenerLoader {\n    constructor(THREE, GraphicsThree3D) {\n      this.THREE = THREE;\n      this.CSG = GraphicsThree3D.CSG;\n      this.fontUrlArray = GraphicsThree3D.fontUrlArray;\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.utils = GraphicsThree3D.utils;\n      this.WireframeGenerator = GraphicsThree3D.WireframeGenerator; ///\n\n      this.drawFasteners = this.drawFasteners.bind(this);\n    }\n\n    drawFasteners() {\n      let jsonData = this.GraphicsThree3D.jsonData;\n      let dxfFastenerPoints = this.GraphicsThree3D.dxfGenerator.fastenerPoints;\n\n      for (let i = 0; i < jsonData.fasteners.length; i++) {\n        this.addToDXFPoints(dxfFastenerPoints, jsonData.fasteners[i]);\n\n        if (jsonData.fasteners[i].components.head && jsonData.fasteners[i].components.head.type > 8) {\n          this.drawClamp(jsonData.fasteners[i]);\n        } else {\n          let meshArray = this.drawFastener(jsonData.fasteners[i]); // meshArray.forEach(obj => this.addToDimChainCollisionDetection(obj));\n\n          for (let a = 0; a < meshArray.length; a++) {\n            this.setTime(meshArray, i, a);\n          }\n        }\n      }\n    }\n\n    addToDXFPoints(dxfFastenerPoints, fastenerData) {\n      if (fastenerData.components.axis && fastenerData.properties.axis && fastenerData.properties.axis.line && fastenerData.properties.axis.point) {\n        let axisLength = fastenerData.components.axis.length;\n        dxfFastenerPoints[fastenerData.id] = {\n          axis: [],\n          addon: []\n        };\n        fastenerData.insertionPoints.forEach(insertionPoint => {\n          let directionVec = this.utils.initVector3(insertionPoint.directionVector1);\n          let startPoint = this.utils.initVector3(insertionPoint.insertionPoint);\n          let endPoint = startPoint.clone().add(directionVec.multiplyScalar(axisLength));\n          let dxfData = {\n            pointPair: [startPoint, endPoint],\n            properties: {\n              line: fastenerData.properties.axis.line,\n              point: fastenerData.properties.axis.point\n            }\n          };\n          dxfFastenerPoints[fastenerData.id].axis.push(dxfData);\n        });\n      }\n    }\n\n    addToDimChainCollisionDetection(obj) {\n      obj.updateMatrix();\n      obj.traverse(child => {\n        if (child.type === \"Mesh\" && !(child.geometry.faceVertexUvs && child.geometry.faceVertexUvs[0].length === 0)) {\n          let intersectionObject = child.clone();\n          intersectionObject.applyMatrix4(obj.matrix);\n          let intersectionObjects = this.GraphicsThree3D.getThreeSideFaceObjects(intersectionObject);\n          this.GraphicsThree3D.DimensionalChainIntersectionDetection.meshArr.push(intersectionObjects);\n        }\n      });\n    }\n\n    drawFastener(fastener) {\n      let meshArray = [];\n\n      if (fastener.components.axis) {\n        let axisData = fastener.components.axis;\n        let shankData = fastener.components.shank;\n        let headData = fastener.components.head;\n        let threadsData = fastener.components.threads;\n        let tipData = fastener.components.tip;\n        let fastenerProps = fastener.properties; // Axis\n\n        let axisGeo, axisPointGeo;\n        let axisMat, axisPointMat;\n        let inversedDirection = false;\n\n        if (axisData.length < 0) {\n          inversedDirection = true;\n          axisData.length *= -1; // maybe change code not to modify json?\n        }\n\n        if (fastenerProps.axis) {\n          if (axisData.length > 0) {\n            let lineProps = fastenerProps.axis.line;\n            if (lineProps.thickness && lineProps.type > 0) axisGeo = this.getAxisGeo(axisData, fastenerProps.axis);\n            axisMat = this.GraphicsThree3D.getMaterialFromColor(lineProps.color);\n          }\n\n          let pointProps = fastenerProps.axis.point;\n          if (pointProps.size) axisPointGeo = this.getAxisPointGeo(pointProps);\n          axisPointMat = this.GraphicsThree3D.getMaterialFromColor(pointProps.color);\n        }\n\n        let headSideLineProps = fastenerProps.fastener.headSide.line;\n        let fastenerMaterial = this.getMaterial(fastener.properties, \"fastener\");\n        let lineMaterial = this.getLineMaterial(headSideLineProps);\n        let headSideMeshes = [];\n        let tipSideMeshes = []; // Heads\n\n        let headGeo = this.getFastenerHeadGeo(headData);\n        let head = this.drawFastenerHead(headData, headGeo, fastenerMaterial);\n        if (head) headSideMeshes.push(head);\n        let drawBottomFrameHead = true;\n\n        if (shankData && head) {\n          if (headData.type == 1 && (shankData.type == 1 || shankData.type == 2 && shankData.size >= headData.bottomDiameter.value)) drawBottomFrameHead = false;\n        }\n\n        let headWireframes;\n        if (headSideLineProps && head) headWireframes = this.makeHeadWireframe(headGeo, headSideLineProps, drawBottomFrameHead);\n\n        if (threadsData) {\n          let threadMaxPoint = threadsData[threadsData.length - 1].insertionDistance + threadsData[threadsData.length - 1].length;\n          if (axisData.length == 0 || threadMaxPoint > axisData.length) axisData.length = threadMaxPoint;\n        }\n\n        let segmentsLeft = [[0, axisData.length]];\n\n        if (head && headData && (headData.type == 1 || headData.type == 2 || headData.type == 6)) {\n          segmentsLeft[0][0] = headData.height.value;\n        }\n\n        if (tipData && tipData.type && tipData.height && (fastenerMaterial || fastenerProps.fastener.tipSide)) {\n          segmentsLeft[0][1] -= tipData.height;\n        }\n\n        let threadSegments = [];\n        if (threadsData) threadsData.forEach(thread => {\n          let minPoint = thread.insertionDistance;\n          let maxPoint = thread.insertionDistance + thread.length;\n\n          if (minPoint < segmentsLeft[0][0]) {\n            minPoint = segmentsLeft[0][0];\n          }\n\n          if (maxPoint > segmentsLeft[0][1]) {\n            maxPoint = segmentsLeft[0][1];\n          }\n\n          let threadParams = {\n            coreDiameter: thread.coreDiameter,\n            distance: thread.distance,\n            height: thread.height,\n            pitch: thread.pitch,\n            threadDiameter: thread.threadDiameter\n          };\n          threadSegments.push([minPoint, maxPoint, threadParams]);\n        });\n        threadSegments.forEach(threadSegment => {\n          let minPoint = threadSegment[0];\n          let maxPoint = threadSegment[1];\n          segmentsLeft.forEach(segment => {\n            if (minPoint > segment[0] && minPoint < segment[1] && maxPoint > segment[0] && maxPoint < segment[1]) {\n              segmentsLeft.push([maxPoint, segment[1]]);\n              segment[1] = minPoint;\n            } else {\n              if (minPoint > segment[0] && minPoint < segment[1]) segment[1] = minPoint;\n              if (maxPoint > segment[0] && maxPoint < segment[1]) segment[0] = maxPoint;\n            }\n          });\n        });\n        let tipDiameter;\n\n        if (threadSegments.length > 0 && segmentsLeft.length > 0) {\n          let lastThreadMax = threadSegments[threadSegments.length - 1][1];\n          let lastShankMax = segmentsLeft[segmentsLeft.length - 1][1];\n          let threadDiameter = threadSegments[threadSegments.length - 1][2].coreDiameter;\n          let shankSize = shankData ? shankData.size : 0;\n          if (lastThreadMax > lastShankMax) tipDiameter = threadDiameter;else if (!shankSize) tipDiameter = threadDiameter;else tipDiameter = shankSize;\n        } else if (threadSegments.length > 0) {\n          tipDiameter = threadSegments[threadSegments.length - 1][2].coreDiameter;\n        } else if (segmentsLeft.length > 0) {\n          tipDiameter = shankData.size;\n        }\n\n        if (tipDiameter == 0) {\n          tipDiameter = headData.bottomDiameter.value;\n        }\n\n        let tipSideProps = fastenerProps.fastener.tipSide;\n        let tipSideMaterial;\n\n        if (shankData && tipSideProps && shankData.tipSideLength) {\n          tipSideMaterial = this.getMaterial(fastenerProps, \"tipSide\");\n          let tipSideStartPoint = axisData.length - shankData.tipSideLength;\n          segmentsLeft.forEach((segment, index) => {\n            let minPoint = segment[0];\n            let maxPoint = segment[1];\n\n            if (tipSideStartPoint > minPoint && tipSideStartPoint < maxPoint) {\n              segmentsLeft.splice(index + 1, 0, [tipSideStartPoint, maxPoint, true]);\n              segment[1] = tipSideStartPoint;\n              segment[2] = false;\n            } else if (tipSideStartPoint < minPoint && tipSideStartPoint < maxPoint) {\n              segment[2] = true;\n            } else {\n              segment[2] = false;\n            }\n          });\n        }\n\n        let shankGeo = this.getFastenerShankGeo(segmentsLeft, fastener.components.shank, fastener);\n        let tipGeo = this.getFastenerTipGeo(fastener.components.tip, tipDiameter, fastener, axisData.length);\n        let isFastenerWithPitch = false;\n        let isFastenerWithoutPitch = false;\n        let cylGeo, spiralGeo, withoutPitchGeo, withoutPitchCylGeo, cylWireframes, coreWireframes;\n        let wireframeWithoutPitchPts, wireframeWithPitchPts;\n        let intersectionThreadMeshes = [];\n\n        if (threadsData) {\n          threadsData.forEach(thread => {\n            if (thread.pitch && !thread.distance) isFastenerWithPitch = true;else if (!thread.pitch && thread.distance) isFastenerWithoutPitch = true;\n          });\n          intersectionThreadMeshes.push(...this.getThreadIntersectionBoxes(threadSegments));\n\n          if (isFastenerWithPitch) {\n            [cylGeo, spiralGeo, wireframeWithPitchPts, cylWireframes] = this.getSpiralAndCylGeo(threadSegments, fastenerProps);\n          }\n\n          if (isFastenerWithoutPitch) {\n            [withoutPitchGeo, withoutPitchCylGeo, wireframeWithoutPitchPts, coreWireframes] = this.getThreadWithoutPitchGeo(threadSegments, fastenerProps);\n          }\n        } // Axis\n\n\n        let axis;\n        if (fastenerProps.axis) axis = this.drawAxis(axisGeo, axisPointGeo, axisMat, axisPointMat, fastener.properties.axis); // Threads\n\n        let threads = [];\n\n        if (threadsData) {\n          if (isFastenerWithPitch) {\n            let [cylinder, spiral] = this.drawFastenerThread_0_WithPitch(cylGeo, spiralGeo, fastenerMaterial, wireframeWithPitchPts, headSideLineProps, lineMaterial);\n            if (cylinder) headSideMeshes.push(cylinder);\n            threads.push(spiral);\n          }\n\n          if (isFastenerWithoutPitch) {\n            let [thread, core] = this.drawFastenerThread_1_WithoutPitch(withoutPitchGeo, withoutPitchCylGeo, fastenerMaterial, wireframeWithoutPitchPts, headSideLineProps);\n            threads.push(thread);\n            if (core) headSideMeshes.push(core);\n          }\n        } // Tip\n\n\n        let drawTopFrameShank = true;\n        let drawBotFrameShank = true;\n        let tipWireframes;\n        let tip = this.drawFastenerTip(tipGeo, fastenerMaterial, tipSideMaterial);\n\n        if (tip) {\n          let drawTopTip = true;\n\n          if (shankData && segmentsLeft[segmentsLeft.length - 1][1] == axisData.length - tipData.height) {\n            if (shankData.type == 1 && (tipData.type == 1 || tipData.type == 2)) {\n              drawTopTip = false;\n              drawBotFrameShank = false;\n            } else if (shankData.type == 2 && (tipData.type == 3 || tipData.type == 4 || tipData.type == 5 || tipData.type == 6)) {\n              drawTopTip = false;\n              drawBotFrameShank = false;\n            }\n          } else if (threadsData && threadSegments && threadSegments[threadSegments.length - 1][1] == axisData.length - tipData.height) {\n            if (tipData.type == 1 || tipData.type == 2) drawTopTip = false;\n          }\n\n          tipWireframes = this.makeTipWireframe(tipData, tipGeo, tipSideProps && shankData.tipSideLength ? tipSideProps.line : headSideLineProps, drawTopTip);\n          if (tip.isTipSide) tipSideMeshes.push(tip);else headSideMeshes.push(tip);\n        }\n\n        if (shankData && head) {\n          let diameterToCompare = headData.bottomDiameter.value !== 0 ? headData.bottomDiameter.value : headData.topDiameter.value;\n          if (headData.wrenchSize) diameterToCompare = headData.wrenchSize;\n\n          if (shankData.type == 1 && diameterToCompare >= shankData.size) {\n            drawTopFrameShank = false;\n          }\n        } // Shank\n\n\n        let [shanks, shankWireframes] = this.drawFastenerShank(fastener.components.shank, fastener.properties, shankGeo, drawTopFrameShank, drawBotFrameShank);\n        shanks.headSide.forEach(shank => {\n          if (shank) headSideMeshes.push(shank);\n        });\n        shanks.tipSide.forEach(shank => {\n          if (shank) tipSideMeshes.push(shank);\n        });\n        let headSideMesh = headSideMeshes.splice(0, 1)[0];\n        let tipSideMesh = tipSideMeshes.splice(0, 1)[0];\n        headSideMeshes.forEach(mesh => {\n          if (mesh) {\n            let firstCSG = this.CSG.fromMesh(headSideMesh);\n            let secondCSG = this.CSG.fromMesh(mesh);\n            let unionCSG = firstCSG.union(secondCSG);\n            let unionMesh = this.CSG.toMesh(unionCSG, new this.THREE.Matrix4());\n            headSideMesh = unionMesh;\n          }\n        });\n        tipSideMeshes.forEach(mesh => {\n          if (mesh) {\n            let firstCSG = this.CSG.fromMesh(tipSideMesh);\n            let secondCSG = this.CSG.fromMesh(mesh);\n            let unionCSG = firstCSG.union(secondCSG);\n            let unionMesh = this.CSG.toMesh(unionCSG, new this.THREE.Matrix4());\n            tipSideMesh = unionMesh;\n          }\n        });\n        if (headSideMesh && fastenerMaterial) headSideMesh.material = fastenerMaterial;\n        if (tipSideMesh && tipSideMaterial) tipSideMesh.material = tipSideMaterial;\n        if (headSideMesh) headSideMesh.material.side = this.THREE.FrontSide;\n        if (tipSideMesh) tipSideMesh.material.side = this.THREE.FrontSide;\n        let backSideHead, backSideTip;\n\n        if (headSideMesh) {\n          let geo = headSideMesh.geometry.clone();\n          let mat = headSideMesh.material.clone();\n          mat.side = this.THREE.BackSide;\n          backSideHead = new this.THREE.Mesh(geo, mat);\n        }\n\n        if (tipSideMesh) {\n          let geo = tipSideMesh.geometry.clone();\n          let mat = tipSideMesh.material.clone();\n          mat.side = this.THREE.BackSide;\n          backSideTip = new this.THREE.Mesh(geo, mat);\n        }\n\n        for (let b = 0; b < fastener.insertionPoints.length; b++) {\n          let intersectionPoint = fastener.insertionPoints[b];\n          let insertionPoint = intersectionPoint.insertionPoint;\n          let insertionVector = new this.THREE.Vector3(insertionPoint.x, insertionPoint.y, insertionPoint.z);\n          let rotationVector = this.utils.normalizeVector(intersectionPoint.directionVector1);\n          let rotationVectorTwo = this.utils.normalizeVector(intersectionPoint.directionVector2);\n          let objectFastener = new this.THREE.Object3D();\n          let clonedHeadSide, clonedTipSide;\n\n          if (headSideMesh) {\n            clonedHeadSide = headSideMesh.clone();\n            objectFastener.add(clonedHeadSide);\n          }\n\n          if (tipSideMesh) {\n            clonedTipSide = tipSideMesh.clone();\n            objectFastener.add(clonedTipSide);\n          }\n\n          if (axis) objectFastener.add(axis.clone());\n          threads.forEach(thread => {\n            if (thread) objectFastener.add(thread.clone());\n          });\n\n          if (backSideHead) {\n            backSideHead = backSideHead.clone();\n            objectFastener.add(backSideHead);\n          }\n\n          if (backSideTip) {\n            backSideTip = backSideTip.clone();\n            objectFastener.add(backSideTip);\n          } // AddOns\n\n\n          let [addOns, addOnDxfPointsData] = this.generateAddons(fastener.components.addOns, fastenerProps.addOn);\n          addOns.forEach(addOn => {\n            if (addOn) {\n              addOn.renderOrder = -2;\n              addOn.isAddOn = true;\n              let backSide = this.drawBacksideMesh(addOn);\n              backSide.renderOrder = -3;\n              addOn.add(backSide);\n              objectFastener.add(addOn);\n            }\n          }); ///\n\n          intersectionThreadMeshes.forEach(mesh => objectFastener.add(mesh.clone())); ///\n\n          if (headWireframes) headWireframes.forEach(wireframeArr => wireframeArr.forEach(mesh => {\n            objectFastener.add(mesh.clone());\n          }));\n          if (shankWireframes) shankWireframes.forEach(wireframe => wireframe.forEach(segment => {\n            objectFastener.add(segment.clone());\n          }));\n          if (tipWireframes) tipWireframes.forEach(wireframeArr => wireframeArr.forEach(wireframe => {\n            objectFastener.add(wireframe.clone());\n          }));\n          if (cylWireframes) cylWireframes.forEach(wireframeArr => wireframeArr.forEach(wireframe => wireframe.forEach(line => objectFastener.add(line.clone()))));\n          if (coreWireframes) coreWireframes.forEach(wireframeArr => wireframeArr.forEach(wireframe => wireframe.forEach(line => objectFastener.add(line.clone()))));\n          let directionVector = new this.THREE.Vector3(rotationVector.x, rotationVector.y, rotationVector.z);\n          let directionVectorTwo = new this.THREE.Vector3(rotationVectorTwo.x, rotationVectorTwo.y, rotationVectorTwo.z);\n\n          if (inversedDirection) {\n            directionVector.negate();\n            directionVectorTwo.negate();\n          }\n\n          if (clonedTipSide) {\n            let objects = {\n              clonedTipSide,\n              backSideTip,\n              clonedHeadSide,\n              backSideHead\n            };\n            let fastenerProps = {\n              axisData,\n              shankData,\n              directionVector,\n              insertionVector\n            };\n            this.removeHeadTipConnection(objects, fastenerProps);\n          }\n\n          objectFastener.children.forEach(child => {\n            if (!child.isAddOn) child.renderOrder = -4;\n          });\n          if (backSideHead) backSideHead.renderOrder = -5;\n          if (backSideTip) backSideTip.renderOrder = -5;\n          this.rotateObject(objectFastener, directionVector, directionVectorTwo);\n          objectFastener.position.set(insertionPoint.x, insertionPoint.y, insertionPoint.z);\n          meshArray.push(objectFastener);\n          this.GraphicsThree3D.addObjectToVisControl(objectFastener, \"fastener\"); // Might need better solution\n\n          objectFastener.updateMatrix();\n          addOnDxfPointsData.forEach(ptData => {\n            if (ptData) {\n              ptData.points.forEach(pts => pts.forEach(pt => pt.applyMatrix4(objectFastener.matrix)));\n              this.GraphicsThree3D.dxfGenerator.fastenerPoints[fastener.id].addon.push(ptData);\n            }\n          });\n        }\n      }\n\n      return meshArray;\n    }\n\n    generateAddons(addOnsDataArr, addOnProps) {\n      let addOns = [];\n      let addOnDxfPointsData = [];\n\n      if (addOnsDataArr) {\n        addOnsDataArr.forEach(addOn => {\n          if (addOn.type == 1) {\n            let [mesh, dxfData] = this.drawPolygonNut(addOn, addOnProps);\n            addOns.push(mesh);\n            addOnDxfPointsData.push(dxfData);\n          } else if (addOn.type == 2) {\n            let [mesh, dxfData] = this.drawCircleWasher(addOn, addOnProps);\n            addOns.push(mesh);\n            addOnDxfPointsData.push(dxfData);\n          } else if (addOn.type == 3) {\n            let [mesh, dxfData] = this.drawRectangleWasher(addOn, addOnProps);\n            addOns.push(mesh);\n            addOnDxfPointsData.push(dxfData);\n          } else if (addOn.type == 4) {\n            let [mesh, dxfData] = this.drawAngleWasherTypeA(addOn, addOnProps);\n            addOns.push(mesh);\n            addOnDxfPointsData.push(dxfData);\n          } else if (addOn.type == 5) {\n            let [mesh, dxfData] = this.drawAngleWasherTypeB(addOn, addOnProps);\n            addOns.push(mesh);\n            addOnDxfPointsData.push(dxfData);\n          } else if (addOn.type == 6) {\n            let [mesh, dxfData] = this.drawFtConnector(addOnProps);\n            addOns.push(mesh);\n            addOnDxfPointsData.push(dxfData);\n          } else console.log(\"AddOn type undefined\");\n        });\n      }\n\n      return [addOns, addOnDxfPointsData];\n    }\n\n    removeHeadTipConnection(objects, fastenerProps) {\n      let axisData = fastenerProps.axisData;\n      let shankData = fastenerProps.shankData;\n      let directionVector = fastenerProps.directionVector;\n      let insertionVector = fastenerProps.insertionVector;\n      let clonedTipSide = objects.clonedTipSide;\n      let backSideTip = objects.backSideTip;\n      let clonedHeadSide = objects.clonedHeadSide;\n      let backSideHead = objects.backSideHead;\n      let shankLength = axisData.length;\n      let tipOffset = shankData.tipSideLength;\n      let planeVector = directionVector.clone().normalize();\n      let positionVector = insertionVector.clone().projectOnVector(planeVector);\n      let positionDistance = -(positionVector.length() + shankLength - tipOffset + 0.0001);\n      let clippingPlane = new this.THREE.Plane(planeVector, positionDistance);\n      clonedTipSide.material.clippingPlanes = [clippingPlane];\n      backSideTip.material.clippingPlanes = [clippingPlane];\n\n      if (clonedHeadSide) {\n        let shankLength = axisData.length;\n        let tipOffset = shankData.tipSideLength;\n        let planeVector = directionVector.clone().negate().normalize();\n        let positionVector = insertionVector.projectOnVector(planeVector);\n        let positionDistance = positionVector.length() + shankLength - tipOffset - 0.0001;\n        let clippingPlane = new this.THREE.Plane(planeVector, positionDistance);\n        clonedHeadSide.material.clippingPlanes = [clippingPlane];\n        backSideHead.material.clippingPlanes = [clippingPlane];\n      }\n    }\n\n    drawDoublesideFrame(geo, lineProps, drawTop = true, drawBot = true, drawEdges = false) {\n      let partOne = [];\n      let partTwo = [];\n      let wireframes = [];\n      let geoVertices = geo.vertices;\n      let firstPart = geoVertices[0].y;\n      geoVertices.forEach(vertex => {\n        if (vertex.y == firstPart) partOne.push(vertex);else partTwo.push(vertex);\n      });\n\n      if (geo.type == \"CylinderGeometry\") {\n        partOne.splice(partOne.length - 1, 1);\n        partTwo.splice(partTwo.length - 1, 1);\n      }\n\n      if (drawTop && partOne.length > 0) {\n        let wireframeOne = this.drawLineFromPoints(partOne, lineProps, true);\n        wireframes.push([wireframeOne]);\n      }\n\n      if (drawBot && partTwo.length > 0) {\n        let wireframeTwo = this.drawLineFromPoints(partTwo, lineProps, true);\n        wireframes.push([wireframeTwo]);\n      }\n\n      if (drawEdges) {\n        let edgesLineArr = this.drawEdgesFrame(partOne, partTwo, lineProps);\n        wireframes.push(edgesLineArr);\n      }\n\n      return wireframes;\n    }\n\n    drawEdgesFrame(partOne, partTwo, lineProps) {\n      // partOne must be array, partTwo can be vector\n      let edgesLineArr = [];\n\n      if (partOne.length > 0) {\n        if (partOne.length == partTwo.length) {\n          for (let i = 0; i < partOne.length; i++) {\n            let line = this.drawLineFromPoints([partOne[i], partTwo[i]], lineProps);\n            edgesLineArr.push(line);\n          }\n        } else {// TODO: vector as point\n        }\n      }\n\n      return edgesLineArr;\n    }\n\n    getThreadIntersectionBoxes(threadSegments) {\n      let boxArr = [];\n      threadSegments.forEach(segmentData => {\n        let boxHeight = segmentData[1] - segmentData[0];\n        let boxWidth = segmentData[2].threadDiameter;\n        let boxGeo = new this.THREE.BoxGeometry(boxWidth, boxHeight, boxWidth);\n        boxGeo.translate(0, -boxHeight / 2 - segmentData[0], 0);\n        let boxMat = new this.THREE.MeshBasicMaterial();\n        let box = new this.THREE.Mesh(boxGeo, boxMat);\n        box.visible = false;\n        boxArr.push(box);\n      });\n      return boxArr;\n    }\n\n    drawFastenerHead(headData, headGeo, fastenerMaterial) {\n      let fastenerHead;\n\n      if (headData) {\n        if (headData.type == 1 || headData.type == 2) {\n          fastenerHead = this.drawFastenerHead_1_Countersunk(headGeo, fastenerMaterial, headData);\n        } else if (headData.type == 3) {\n          fastenerHead = this.drawFastenerHead_3_Lentil(headGeo, fastenerMaterial, headData);\n        } else if (headData.type == 4) {\n          fastenerHead = this.drawFastenerHead_4_DiscFlat(headGeo, fastenerMaterial, headData);\n        } else if (headData.type == 5) {\n          fastenerHead = this.drawFastenerHead_5_DiscBottomFlat(headGeo, fastenerMaterial, headData);\n        } else if (headData.type == 6) {\n          fastenerHead = this.drawFastenerHead_6_DiscTopFlat(headGeo, fastenerMaterial, headData);\n        } else if (headData.type == 7) {\n          fastenerHead = this.drawFastenerHead_7_PolygonWithoutWasher(headGeo, fastenerMaterial, headData);\n        } else if (headData.type == 8) {\n          fastenerHead = this.drawFastenerHead_8_PolygonWithWasher(headGeo, fastenerMaterial, headData);\n        } else {\n          console.log(\"Head type undefined\");\n        }\n      } else {\n        fastenerHead = null;\n      }\n\n      return fastenerHead;\n    }\n\n    drawBacksideMesh(mesh) {\n      let geo = mesh.geometry.clone();\n      let mat = mesh.material.clone();\n      mat.side = this.THREE.BackSide;\n      let backsideMesh = new this.THREE.Mesh(geo, mat);\n      return backsideMesh;\n    }\n\n    getAddonDxfData_PolygonWireframe(addonMesh, addonWireframes, addOnProps) {\n      let ptsArr = [];\n      addonWireframes.forEach(wireframe => wireframe.forEach(line => {\n        let pts = this.utils.getVerticesFromBufferGeometry(line.geometry);\n        if (line.type === \"LineLoop\") pts.push(pts[0].clone());\n        pts.forEach(pt => pt.applyMatrix4(addonMesh.matrix));\n        ptsArr.push(pts);\n      }));\n      return {\n        points: ptsArr,\n        properties: addOnProps.line\n      };\n    }\n\n    getAddonDxfData_CircleWasher(addonMesh, addonWireframes, addOnProps) {\n      let ptsArr = [];\n      let sidePoints = [];\n      addonWireframes.forEach(wireframe => wireframe.forEach(line => {\n        let pts = this.utils.getVerticesFromBufferGeometry(line.geometry);\n\n        if (pts.length > 0) {\n          pts.push(pts[0].clone());\n          pts.forEach(pt => pt.applyMatrix4(addonMesh.matrix));\n          ptsArr.push(pts);\n        }\n      }));\n\n      if (ptsArr.length === 2) {\n        ptsArr[0].forEach((point, idx) => sidePoints.push([point.clone(), ptsArr[1][idx].clone()]));\n        ptsArr.push(...sidePoints);\n      }\n\n      return {\n        points: ptsArr,\n        properties: addOnProps.line\n      };\n    }\n\n    drawPolygonNut(addOnData, addOnProps) {\n      let mesh, dxfData;\n\n      if (addOnData.height > 0 && addOnData.numberOfEdges > 2 && addOnProps && addOnData.wrenchSize > 0) {\n        let insertionDistance = addOnData.insertionDistance;\n        let height = addOnData.height;\n        let wrenchSize = addOnData.wrenchSize / 2;\n        let numberOfEdges = addOnData.numberOfEdges;\n        let angle = (numberOfEdges - 2) * 180 / numberOfEdges / 2;\n        angle *= Math.PI / 180;\n        let radius = wrenchSize / Math.sin(angle);\n        let geometry = new this.THREE.CylinderGeometry(radius, radius, height, numberOfEdges);\n        geometry.rotateY(Math.PI / 6); //temp\n\n        geometry.translate(0, -height / 2, 0);\n        geometry.isPolygon = true;\n        let volumeColor = addOnProps.volume.color;\n        let volumeMaterial = this.GraphicsThree3D.getMaterialFromColor(volumeColor);\n        mesh = new this.THREE.Mesh(geometry, volumeMaterial); ///\n\n        let lineProps = addOnProps.line;\n        let addonWireframes = this.makeHeadWireframe(geometry, lineProps);\n        addonWireframes.forEach(wireframe => wireframe.forEach(line => mesh.add(line))); ///\n\n        mesh.position.set(0, -insertionDistance, 0);\n        mesh.updateMatrix();\n        dxfData = this.getAddonDxfData_PolygonWireframe(mesh, addonWireframes, addOnProps);\n      }\n\n      return [mesh, dxfData];\n    }\n\n    drawCircleWasher(addOnData, addOnProps) {\n      let mesh, dxfData;\n\n      if (addOnData.height > 0 && addOnProps) {\n        let insertionDistance = addOnData.insertionDistance;\n        let height = addOnData.height;\n        let topRadius = addOnData.topDiameter / 2;\n        let botRadius = addOnData.bottomDiameter / 2;\n\n        if (topRadius > 0 || botRadius > 0) {\n          let geometry = new this.THREE.CylinderGeometry(topRadius, botRadius, height, 32);\n          geometry.translate(0, -height / 2, 0);\n          geometry.isAddOn = true;\n          let volumeColor = addOnProps.volume.color;\n          let volumeMaterial = this.GraphicsThree3D.getMaterialFromColor(volumeColor);\n          volumeMaterial.side = this.THREE.FrontSide;\n          mesh = new this.THREE.Mesh(geometry, volumeMaterial); ///\n\n          let lineProps = addOnProps.line;\n          let addonWireframes = this.makeHeadWireframe(geometry, lineProps);\n          addonWireframes.forEach(wireframe => wireframe.forEach(line => mesh.add(line))); ///\n\n          mesh.position.set(0, -insertionDistance, 0);\n          mesh.updateMatrix();\n          dxfData = this.getAddonDxfData_CircleWasher(mesh, addonWireframes, addOnProps);\n        }\n      }\n\n      return [mesh, dxfData];\n    }\n\n    drawRectangleWasher(addOnData, addOnProps) {\n      let mesh, dxfData;\n\n      if (addOnData.width > 0 && addOnData.length > 0 && addOnData.height > 0 && addOnProps) {\n        let insertionDistance = addOnData.insertionDistance + 0.001;\n        let width = addOnData.width;\n        let length = addOnData.length;\n        let height = addOnData.height;\n        let geometry = new this.THREE.BoxGeometry(length, height, width);\n        geometry.translate(0, -height / 2, 0);\n        let volumeColor = addOnProps.volume.color;\n        let lineProps = addOnProps.line;\n        let volumeMaterial = this.GraphicsThree3D.getMaterialFromColor(volumeColor);\n        volumeMaterial.side = this.THREE.FrontSide;\n        mesh = new this.THREE.Mesh(geometry, volumeMaterial); ///\n\n        let partOne = [];\n        let partTwo = [];\n        let geoVertices = geometry.vertices;\n        let firstPart = geoVertices[0].y;\n        geoVertices.forEach(vertex => {\n          if (vertex.y == firstPart) partOne.push(vertex);else partTwo.push(vertex);\n        });\n        let wireframeOne = this.drawLineFromPoints(partOne, lineProps, true);\n        let wireframeTwo = this.drawLineFromPoints(partTwo, lineProps, true);\n        mesh.add(wireframeOne);\n        mesh.add(wireframeTwo);\n        let edgesLineArr = [];\n\n        for (let i = 0; i < partOne.length; i++) {\n          let newLine = this.drawLineFromPoints([partOne[i], partTwo[i]], lineProps);\n          edgesLineArr.push(newLine);\n        }\n\n        edgesLineArr.forEach(line => mesh.add(line)); ///\n\n        mesh.position.set(0, -insertionDistance, 0);\n        mesh.updateMatrix();\n        let ptsArr = [];\n        let partOneClone = partOne.map(pt => pt.clone().applyMatrix4(mesh.matrix));\n        let partTwoClone = partTwo.map(pt => pt.clone().applyMatrix4(mesh.matrix));\n        let edgePoints = partOneClone.reduce((ptsArr, pt, i) => {\n          ptsArr.push([pt.clone(), partTwoClone[i].clone()]);\n          return ptsArr;\n        }, []);\n        partOneClone.push(partOneClone[0].clone());\n        partTwoClone.push(partTwoClone[0].clone());\n        ptsArr.push(partOneClone, partTwoClone, ...edgePoints);\n        dxfData = {\n          points: ptsArr,\n          properties: addOnProps.line\n        };\n      }\n\n      return [mesh, dxfData];\n    }\n\n    drawAngleWasherTypeA(addOnData, addOnProps) {\n      let mesh, dxfData;\n\n      if (addOnProps && addOnData.length && addOnData.width && addOnData.height && addOnData.normalLength && addOnData.orthogonalLength) {\n        let insertionDistance = addOnData.insertionDistance + 0.001;\n        let orthogonalLength = addOnData.orthogonalLength;\n        let height = addOnData.height;\n        let length = addOnData.length;\n        let width = addOnData.width;\n        let BT = Math.round(Math.sqrt(orthogonalLength / 2 * (orthogonalLength / 2) / 2) * 100) / 100;\n        let A = {\n          x: -BT,\n          y: BT - height\n        };\n        let B = {\n          x: -BT,\n          y: -BT\n        };\n        let C = {\n          x: BT,\n          y: BT\n        };\n        let D = {\n          x: length - BT,\n          y: BT - height\n        };\n        let pts = [];\n        pts.push(new this.THREE.Vector2(A.x, A.y));\n        pts.push(new this.THREE.Vector2(B.x, B.y));\n        pts.push(new this.THREE.Vector2(C.x, C.y));\n        pts.push(new this.THREE.Vector2(D.x, D.y));\n        let shape = new this.THREE.Shape(pts);\n        let extrudeSettings = {\n          depth: width,\n          bevelEnabled: false\n        };\n        let geometry = new this.THREE.ExtrudeGeometry(shape, extrudeSettings);\n        let volumeColor = addOnProps.volume.color;\n        let lineProps = addOnProps.line;\n        let volumeMaterial = this.GraphicsThree3D.getMaterialFromColor(volumeColor);\n        mesh = new this.THREE.Mesh(geometry, volumeMaterial); ///\n\n        let pointsArr = pts.map(point => new this.THREE.Vector3(point.x, point.y, width));\n        let polygonWirefame = this.makePolygonWireframe(pointsArr, width, lineProps);\n        polygonWirefame.forEach(wireframe => wireframe.forEach(line => mesh.add(line))); ///\n\n        mesh.rotation.set(0, -Math.PI / 2, -Math.PI / 4);\n        mesh.position.set(width / 2, -insertionDistance, 0);\n        mesh.updateMatrix();\n        dxfData = this.getAddonDxfData_PolygonWireframe(mesh, polygonWirefame, addOnProps);\n      }\n\n      return [mesh, dxfData];\n    }\n\n    drawAngleWasherTypeB(addOnData, addOnProps) {\n      let mesh, dxfData;\n\n      if (addOnData.height && addOnData.width && addOnData.length && addOnData.normalLength && addOnData.orthogonalLength) {\n        let height = addOnData.height;\n        let length = addOnData.length;\n        let width = addOnData.width;\n        let ellipsoidgeometry = new this.THREE.Geometry();\n        let latitudeBands = 32,\n            longitudeBands = 32,\n            a = length / 2,\n            b = width / 2,\n            c = height,\n            size = 1;\n\n        for (let latNumber = 0; latNumber <= latitudeBands; latNumber++) {\n          let theta = latNumber * Math.PI / latitudeBands;\n          let sinTheta = Math.sin(theta);\n          let cosTheta = Math.cos(theta);\n\n          for (let longNumber = 0; longNumber <= longitudeBands; longNumber++) {\n            let phi = longNumber * 2 * Math.PI / longitudeBands;\n            let sinPhi = Math.sin(phi);\n            let cosPhi = Math.cos(phi);\n            let x = a * cosPhi * cosTheta;\n            let z = b * cosTheta * sinPhi;\n            let y = c * sinTheta;\n            ellipsoidgeometry.vertices.push(new this.THREE.Vector3(x * size, y * size, z * size));\n          }\n        }\n\n        for (let latNumber = 0; latNumber < latitudeBands; latNumber++) {\n          for (let longNumber = 0; longNumber < longitudeBands; longNumber++) {\n            let first = latNumber * (longitudeBands + 1) + longNumber;\n            let second = first + longitudeBands + 1;\n            ellipsoidgeometry.faces.push(new this.THREE.Face3(first, second, first + 1));\n            ellipsoidgeometry.faces.push(new this.THREE.Face3(second, second + 1, first + 1));\n          }\n        }\n\n        ellipsoidgeometry.computeFaceNormals();\n        let orthogonalLength = addOnData.orthogonalLength;\n        let normalLength = addOnData.normalLength;\n        let normalHeight = Math.sqrt(Math.pow(normalLength, 2) / 2);\n        let heightProportion = normalHeight / (height / 2);\n        let offsetX = Math.sqrt(Math.pow(orthogonalLength / 2, 2) / 2);\n        ellipsoidgeometry.translate(length / 2 - offsetX, -(height / 2) * heightProportion, 0);\n        ellipsoidgeometry.rotateZ(-Math.PI / 4);\n        ellipsoidgeometry.rotateY(-Math.PI / 2);\n        let volumeColor = addOnProps.volume.color;\n        let volumeMaterial = this.GraphicsThree3D.getMaterialFromColor(volumeColor);\n        mesh = new this.THREE.Mesh(ellipsoidgeometry, volumeMaterial);\n        let botCircleGeo = new this.THREE.CircleGeometry(b, 32);\n        botCircleGeo.applyMatrix4(new this.THREE.Matrix4().makeScale(1, a / b, 1));\n        botCircleGeo.rotateY(Math.PI / 2);\n        botCircleGeo.rotateZ(Math.PI / 2);\n        botCircleGeo.translate(length / 2 - offsetX, -(height / 2) * heightProportion, 0);\n        botCircleGeo.rotateZ(-Math.PI / 4);\n        botCircleGeo.rotateY(-Math.PI / 2);\n        let botCircle = new this.THREE.Mesh(botCircleGeo, volumeMaterial);\n        mesh.add(botCircle);\n\n        if (addOnProps.line) {\n          let wireframePoints = this.getEllipsePointsXZ(a, b, 0, {\n            x: 0,\n            y: 0,\n            z: 0\n          });\n          let wireframe = this.drawLineFromPoints(wireframePoints, addOnProps.line, true);\n          wireframe.geometry.rotateZ(Math.PI / 2);\n          wireframe.geometry.translate(length / 2 - offsetX, -(height / 2) * heightProportion, 0);\n          wireframe.geometry.rotateZ(-Math.PI / 4);\n          wireframe.geometry.rotateY(-Math.PI / 2);\n          mesh.add(wireframe);\n        }\n\n        mesh.updateMatrix();\n        let ptsArr = [];\n        this.WireframeGenerator.getWireframeLinePairs(ellipsoidgeometry, Math.PI / 360).forEach(([_, ptPairs]) => ptPairs.forEach(pair => {\n          ptsArr.push(pair.map(pt => pt.clone().applyMatrix4(mesh.matrix)));\n        }));\n        dxfData = {\n          points: ptsArr,\n          properties: addOnProps.line\n        };\n      }\n\n      return [mesh, dxfData];\n    }\n\n    drawFtConnector(addOnProps) {\n      // TODO: CLEAN MESS!!!\n      let csg = this.GraphicsThree3D.CSG;\n      const colorAxis = addOnProps.volume.color;\n      const lineProps = addOnProps.line;\n      let addonMaterial = this.GraphicsThree3D.getMaterialFromColor(colorAxis);\n      addonMaterial.side = this.THREE.FrontSide; // top cyl\n\n      let topCylRadius = 1.25;\n      let topCylHeight = 8;\n      let topCylPosition = new this.THREE.Vector3(0, 4.2, 0); // bot cyl\n\n      let botCylRadius = 0.75;\n      let botCylHeight = 10;\n      let botCylPosition = new this.THREE.Vector3(0, -5.8, 0); // box one\n\n      let boxOneWidth = 3;\n      let boxOneHeight = 0.2;\n      let boxOneDepth = 4;\n      let boxOnePosition = new this.THREE.Vector3(0, 0.1, 0); // box two\n\n      let boxTwoWidth = 5;\n      let boxTwoHeight = 0.6;\n      let boxTwoDepth = 6;\n      let boxTwoPosition = new this.THREE.Vector3(0, -0.3, 0); // box three\n\n      let boxThreeWidth = 3;\n      let boxThreeHeight = 0.2;\n      let boxThreeDepth = 4;\n      let boxThreePosition = new this.THREE.Vector3(0, -0.7, 0); // box four\n\n      let boxFourWidth = 3;\n      let boxFourHeight = 0.2;\n      let boxFourDepth = 4;\n      let boxFourPosition = new this.THREE.Vector3(-2.747, -1.431, 0);\n      let boxFourRotationZ = 30 * Math.PI / 180; // box five\n\n      let boxFiveWidth = 11;\n      let boxFiveHeight = 0.2;\n      let boxFiveDepth = 4;\n      let boxFivePosition = new this.THREE.Vector3(-1.258, -6.808, 0);\n      let boxFiveRotationZ = -60 * Math.PI / 180; // eraser box top\n\n      let eraserBoxTopWidth = 7;\n      let eraserBoxTopHeight = 7;\n      let eraserBoxTopDepth = 7;\n      let eraserBoxTopPosition = new this.THREE.Vector3(2.611, 7.314, 0);\n      let eraserBoxTopRotationZ = 30 * Math.PI / 180; // eraser box bot\n\n      let eraserBoxBotWidth = 4;\n      let eraserBoxBotHeight = 4;\n      let eraserBoxBotDepth = 4;\n      let eraserBoxBotPosition = new this.THREE.Vector3(-1.416, -10.393, 0);\n      let eraserBoxBotRotationZ = -60 * Math.PI / 180; // eraser cyl top\n\n      let eraserCylTopRadius = 0.75;\n      let eraserCylTopHeight = 12;\n      let eraserCylTopPosition = new this.THREE.Vector3(0, 5.9, 0); // meshes\n\n      let topCylGeo = new this.THREE.CylinderGeometry(topCylRadius, topCylRadius, topCylHeight, 32);\n      let topCyl = new this.THREE.Mesh(topCylGeo);\n      topCyl.position.copy(topCylPosition);\n      topCyl.updateMatrix();\n      let botCylGeo = new this.THREE.CylinderGeometry(botCylRadius, botCylRadius, botCylHeight, 32);\n      let botCyl = new this.THREE.Mesh(botCylGeo);\n      botCyl.position.copy(botCylPosition);\n      botCyl.updateMatrix();\n      let boxOneGeo = new this.THREE.BoxGeometry(boxOneWidth, boxOneHeight, boxOneDepth);\n      let boxOne = new this.THREE.Mesh(boxOneGeo);\n      boxOne.position.copy(boxOnePosition);\n      boxOne.updateMatrix();\n      let boxTwoGeo = new this.THREE.BoxGeometry(boxTwoWidth, boxTwoHeight, boxTwoDepth);\n      let boxTwo = new this.THREE.Mesh(boxTwoGeo);\n      boxTwo.position.copy(boxTwoPosition);\n      boxTwo.updateMatrix();\n      let boxThreeGeo = new this.THREE.BoxGeometry(boxThreeWidth, boxThreeHeight, boxThreeDepth);\n      let boxThree = new this.THREE.Mesh(boxThreeGeo);\n      boxThree.position.copy(boxThreePosition);\n      boxThree.updateMatrix();\n      boxFourWidth = 3.4;\n      boxFourPosition = new this.THREE.Vector3(-2.747, -1.4, 0);\n      let boxFourGeo = new this.THREE.BoxGeometry(boxFourWidth, boxFourHeight, boxFourDepth);\n      let boxFour = new this.THREE.Mesh(boxFourGeo);\n      boxFour.rotation.z = boxFourRotationZ;\n      boxFour.position.copy(boxFourPosition);\n      boxFour.updateMatrix();\n      boxFivePosition = new this.THREE.Vector3(-1.408, -6.92, 0);\n      let boxFiveGeo = new this.THREE.BoxGeometry(boxFiveWidth, boxFiveHeight, boxFiveDepth);\n      let boxFive = new this.THREE.Mesh(boxFiveGeo);\n      boxFive.rotation.z = boxFiveRotationZ;\n      boxFive.position.copy(boxFivePosition);\n      boxFive.updateMatrix(); // erasers\n\n      let eraserBoxTopGeo = new this.THREE.BoxGeometry(eraserBoxTopWidth, eraserBoxTopHeight, eraserBoxTopDepth);\n      let eraserBoxTop = new this.THREE.Mesh(eraserBoxTopGeo);\n      eraserBoxTop.rotation.z = eraserBoxTopRotationZ;\n      eraserBoxTop.position.copy(eraserBoxTopPosition);\n      eraserBoxTop.updateMatrix();\n      eraserBoxBotPosition = new this.THREE.Vector3(-1.5, -10.6, 0);\n      let eraserBoxBotGeo = new this.THREE.BoxGeometry(eraserBoxBotWidth, eraserBoxBotHeight, eraserBoxBotDepth);\n      let eraserBoxBot = new this.THREE.Mesh(eraserBoxBotGeo);\n      eraserBoxBot.rotation.z = eraserBoxBotRotationZ;\n      eraserBoxBot.position.copy(eraserBoxBotPosition);\n      eraserBoxBot.updateMatrix();\n      let eraserCylTopGeo = new this.THREE.CylinderGeometry(eraserCylTopRadius, eraserCylTopRadius, eraserCylTopHeight, 32);\n      let eraserCylTop = new this.THREE.Mesh(eraserCylTopGeo);\n      eraserCylTop.position.copy(eraserCylTopPosition);\n      eraserCylTop.updateMatrix(); // wireframes\n\n      let boxOneVertices = boxOneGeo.clone().applyMatrix4(boxOne.matrix).vertices;\n      boxOneVertices = [boxOneVertices[0], boxOneVertices[2], boxOneVertices[7], boxOneVertices[5]];\n      let boxTwoVertices = boxTwoGeo.clone().applyMatrix4(boxTwo.matrix).vertices;\n      boxTwoVertices = [boxTwoVertices[0], boxTwoVertices[2], boxTwoVertices[7], boxTwoVertices[5]];\n      let boxThreeVertices = boxThreeGeo.clone().applyMatrix4(boxThree.matrix).vertices;\n      let boxFourVertices = boxFourGeo.clone().applyMatrix4(boxFour.matrix).vertices;\n      let polyVertices = [boxThreeVertices[0], boxThreeVertices[2], new this.THREE.Vector3(-1.51, -0.8, 2.002), new this.THREE.Vector3(-3.997, -2.2365, 2.002), new this.THREE.Vector3(1.432, -11.634, 2.002), new this.THREE.Vector3(1.254, -11.736, 2.002), boxFourVertices[5], new this.THREE.Vector3(-1.565, -0.6, 2.002)]; // let botCylVertices = botCylGeo.clone().applyMatrix4(botCyl.matrix).vertices.splice(0, 32);\n      // let topCylVertices = topCylGeo.clone().applyMatrix4(topCyl.matrix).vertices.splice(32, 32);\n      // let topCutMiddleVertices = this.getEllipsePointsXZ(1.5, 0.75, 30*Math.PI/180, {x: 0, y: 4.85, z: 0});\n\n      let topCutOuterVertices = this.getEllipsePointsXZ(2.5, 1.25, 30 * Math.PI / 180, {\n        x: 0,\n        y: 4.85,\n        z: 0\n      });\n      let botCutVertices = this.getEllipsePointsXZ(1.5, 0.75, 30 * Math.PI / 180, {\n        x: 0,\n        y: -9.15,\n        z: 0\n      });\n      let botCutWireframes = this.drawLineFromPoints(botCutVertices, lineProps, true);\n      let topCutOuterWireframes = this.drawLineFromPoints(topCutOuterVertices, lineProps, true); // let topCutMiddleWireframes = this.drawLineFromPoints(topCutMiddleVertices, lineProps, true);\n      // let topCylBotWireframes = this.drawLineFromPoints(topCylVertices, lineProps, true);\n      // let botCylTopWireframes = this.drawLineFromPoints(botCylVertices, lineProps, true);\n\n      let boxOneWireframes = this.makePolygonWireframe(boxOneVertices, boxOneDepth, lineProps);\n      let boxTwoWireframes = this.makePolygonWireframe(boxTwoVertices, boxTwoDepth, lineProps);\n      let botPolyWireframes = this.makePolygonWireframe(polyVertices, boxOneDepth, lineProps); // boolean operations\n      // TODO: Optimize!!!\n\n      let eraserBoxTopCSG = csg.fromMesh(eraserBoxTop);\n      let topCylCSG = csg.fromMesh(topCyl);\n      topCylCSG = topCylCSG.subtract(eraserBoxTopCSG);\n      topCyl = csg.toMesh(topCylCSG, new this.THREE.Matrix4());\n      let eraserBoxBotCSG = csg.fromMesh(eraserBoxBot);\n      let botCylCSG = csg.fromMesh(botCyl);\n      botCylCSG = botCylCSG.subtract(eraserBoxBotCSG);\n      botCyl = csg.toMesh(botCylCSG, new this.THREE.Matrix4());\n      let eraserCylTopCSG = csg.fromMesh(eraserCylTop);\n      topCylCSG = csg.fromMesh(topCyl);\n      let boxOneCSG = csg.fromMesh(boxOne);\n      let boxTwoCSG = csg.fromMesh(boxTwo);\n      topCylCSG = topCylCSG.subtract(eraserCylTopCSG);\n      boxOneCSG = boxOneCSG.subtract(eraserCylTopCSG);\n      boxTwoCSG = boxTwoCSG.subtract(eraserCylTopCSG);\n      topCyl = csg.toMesh(topCylCSG, new this.THREE.Matrix4());\n      boxOne = csg.toMesh(boxOneCSG, new this.THREE.Matrix4());\n      boxTwo = csg.toMesh(boxTwoCSG, new this.THREE.Matrix4());\n      topCylCSG = csg.fromMesh(topCyl);\n      botCylCSG = csg.fromMesh(botCyl);\n      boxOneCSG = csg.fromMesh(boxOne);\n      boxTwoCSG = csg.fromMesh(boxTwo);\n      let boxThreeCSG = csg.fromMesh(boxThree);\n      let boxFourCSG = csg.fromMesh(boxFour);\n      let boxFiveCSG = csg.fromMesh(boxFive);\n      let unionCSG = topCylCSG.union(boxOneCSG);\n      unionCSG = unionCSG.union(boxTwoCSG);\n      unionCSG = unionCSG.union(boxThreeCSG);\n      unionCSG = unionCSG.union(botCylCSG);\n      unionCSG = unionCSG.union(boxFourCSG);\n      unionCSG = unionCSG.union(boxFiveCSG);\n      let addon = csg.toMesh(unionCSG, new this.THREE.Matrix4());\n      boxOneWireframes.forEach(wireframe => wireframe.forEach(line => addon.add(line)));\n      boxTwoWireframes.forEach(wireframe => wireframe.forEach(line => addon.add(line)));\n      botPolyWireframes.forEach(wireframe => wireframe.forEach(line => addon.add(line))); // addon.add(botCylTopWireframes);\n      // addon.add(topCylBotWireframes);\n      // addon.add(topCutMiddleWireframes);\n\n      addon.add(topCutOuterWireframes);\n      addon.add(botCutWireframes);\n      addon.rotation.y = -Math.PI / 2;\n      addon.material = addonMaterial;\n      addon.updateMatrix();\n      let ptsArr = [];\n      let ptPairs_TopCyl = this.WireframeGenerator.getRegularWireframePointPairs(topCyl, Math.PI / 360);\n      let ptPairs_BotCyl = this.WireframeGenerator.getRegularWireframePointPairs(botCyl, Math.PI / 360);\n      ptPairs_TopCyl.forEach(pair => ptsArr.push(pair.map(pt => pt.clone().applyMatrix4(addon.matrix))));\n      ptPairs_BotCyl.forEach(pair => ptsArr.push(pair.map(pt => pt.clone().applyMatrix4(addon.matrix))));\n      [boxOneWireframes, boxTwoWireframes, botPolyWireframes].forEach(wireframe => wireframe.forEach(lineArr => lineArr.forEach(line => {\n        let pts = this.utils.getVerticesFromBufferGeometry(line.geometry);\n        if (line.type === \"LineLoop\") pts.push(pts[0].clone());\n        pts.forEach(pt => pt.applyMatrix4(addon.matrix));\n        ptsArr.push(pts);\n      })));\n      let dxfData = {\n        points: ptsArr,\n        properties: addOnProps.line\n      };\n      return [addon, dxfData];\n    }\n\n    makePolygonWireframe(pointsArr, depth, lineProps) {\n      let wireframes = [];\n      let partOne = pointsArr;\n      let partTwo = pointsArr.map(point => point.clone().sub(new this.THREE.Vector3(0, 0, depth)));\n      let wireframeOne = this.drawLineFromPoints(partOne, lineProps, true);\n      wireframes.push([wireframeOne]);\n      let wireframeTwo = this.drawLineFromPoints(partTwo, lineProps, true);\n      wireframes.push([wireframeTwo]);\n      let edgesLineArr = [];\n\n      for (let i = 0; i < partOne.length; i++) {\n        let newLine = this.drawLineFromPoints([partOne[i], partTwo[i]], lineProps);\n        edgesLineArr.push(newLine);\n      }\n\n      wireframes.push(edgesLineArr);\n      return wireframes;\n    }\n\n    drawAxis(axisGeo, axisPointGeo, axisMat, axisPointMat) {\n      let axis = new this.THREE.Object3D();\n      let axisMesh, axisPointMesh;\n      if (axisGeo) axisMesh = new this.THREE.Mesh(axisGeo, axisMat);\n      if (axisPointGeo) axisPointMesh = new this.THREE.Mesh(axisPointGeo, axisPointMat);\n      if (axisGeo) axisMesh.renderOrder = -6;\n      if (axisPointGeo) axisPointMesh.renderOrder = -6;\n      if (axisMesh) axis.add(axisMesh);\n      if (axisPointMesh) axis.add(axisPointMesh);\n      return axis;\n    }\n\n    getMaterial(properties, target) {\n      let jsonColor;\n\n      if (target == \"axis\") {\n        jsonColor = properties.fastener.axis.line.color;\n      } else if (target == \"tipSide\") {\n        jsonColor = properties.fastener.tipSide.volume.color;\n      } else {\n        jsonColor = properties.fastener.headSide.volume.color;\n      }\n\n      let volumeColor = \"rgb(\" + jsonColor.red + \",\" + jsonColor.green + \",\" + jsonColor.blue + \")\";\n      let transparency = jsonColor.alpha / 255;\n      let material = new this.THREE.MeshBasicMaterial({\n        color: volumeColor,\n        opacity: transparency,\n        transparent: true,\n        side: this.THREE.DoubleSide\n      });\n      return material;\n    } // radiuses are for 2D\n\n\n    makeElipsoidGeo(radiusX, radiusY, height) {\n      let geometry = new this.THREE.Geometry();\n      let latitudeBands = 32,\n          longitudeBands = 32,\n          a = radiusX,\n          b = radiusY,\n          c = height,\n          size = 1;\n\n      for (let latNumber = 0; latNumber <= latitudeBands; latNumber++) {\n        let theta = latNumber * Math.PI / latitudeBands;\n        let sinTheta = Math.sin(theta);\n        let cosTheta = Math.cos(theta);\n\n        for (let longNumber = 0; longNumber <= longitudeBands; longNumber++) {\n          let phi = longNumber * 2 * Math.PI / longitudeBands;\n          let sinPhi = Math.sin(phi);\n          let cosPhi = Math.cos(phi);\n          let x = a * cosPhi * cosTheta;\n          let z = b * cosTheta * sinPhi;\n          let y = c * sinTheta;\n          geometry.vertices.push(new this.THREE.Vector3(x * size, y * size, z * size));\n        }\n      }\n\n      for (let latNumber = 0; latNumber < latitudeBands; latNumber++) {\n        for (let longNumber = 0; longNumber < longitudeBands; longNumber++) {\n          let first = latNumber * (longitudeBands + 1) + longNumber;\n          let second = first + longitudeBands + 1;\n          geometry.faces.push(new this.THREE.Face3(first, second, first + 1));\n          geometry.faces.push(new this.THREE.Face3(second, second + 1, first + 1));\n        }\n      }\n\n      geometry.computeFaceNormals();\n      return geometry;\n    } // Geometries\n\n\n    getAxisGeo(axisData, axisProps) {\n      const PRECISION = 8;\n      let axisLength = axisData.length;\n      let axisWidth = axisProps.line.thickness / 2;\n      let axisGeo = new this.THREE.CylinderBufferGeometry(axisWidth, axisWidth, axisLength, PRECISION);\n      axisGeo.translate(0, -axisLength / 2, 0);\n      return axisGeo;\n    }\n\n    getAxisPointGeo(axisProps) {\n      const PRECISION = 8;\n      let pointRadius = axisProps.size / 2;\n      let pointGeo = new this.THREE.SphereBufferGeometry(pointRadius, PRECISION, PRECISION);\n      return pointGeo;\n    }\n    /**\n     * Head Types\n     * 1: Countersunk\n     * 2: Cylinder\n     * 3: Lentil\n     * 4: Disk Flat\n     * 5: Disk Bottom Flat\n     * 6: Disk Top Flat\n     * 7: polygonWithoutWasher\n     * 8: polygonWithWasher\n     */\n\n\n    getFastenerHeadGeoCountersunk(topRadius, bottomRadius, height, radialSegments) {\n      let headGeo = new this.THREE.CylinderGeometry(topRadius, bottomRadius, height, radialSegments);\n      headGeo.translate(0, -height / 2, 0);\n      return headGeo;\n    }\n\n    getFastenerHeadGeoCylinder(topRadius, height, radialSegments) {\n      let headGeo = new this.THREE.CylinderGeometry(topRadius, topRadius, height, radialSegments);\n      headGeo.translate(0, -height / 2, 0);\n      return headGeo;\n    }\n\n    getFastenerHeadGeoLentil(topRadius, height, heightFactor, radialSegments) {\n      let topHeight = height * heightFactor;\n      let botHeight = height - topHeight; // let headGeoTop = this.makeElipsoidGeo(topRadius, topRadius, topHeight);\n\n      let headGeoTop = new this.THREE.SphereGeometry(topRadius, 24, 12);\n      headGeoTop.applyMatrix4(new this.THREE.Matrix4().makeScale(1, topHeight / topRadius, 1));\n      let headGeoBot = new this.THREE.CylinderGeometry(topRadius, topRadius, botHeight, radialSegments);\n      headGeoTop.translate(0, botHeight, 0);\n      headGeoBot.translate(0, botHeight / 2, 0);\n      return [headGeoTop, headGeoBot];\n    }\n\n    getFastenerHeadGeoDiskFlat(topRadius, height, radialSegments) {\n      let headGeo = new this.THREE.CylinderGeometry(topRadius, topRadius, height, radialSegments);\n      headGeo.translate(0, height / 2, 0);\n      return headGeo;\n    }\n\n    getFastenerHeadGeoDiskBottomFlat(topRadius, bottomRadius, topDiameterFactor, topDiameter, height, heightFactor, radialSegments) {\n      let topHeight = height * heightFactor;\n      let botHeight = height - topHeight;\n      let headGeoTop = new this.THREE.CylinderGeometry(topRadius, (topDiameter + 2 * topDiameterFactor * topDiameter) / 2, topHeight, radialSegments);\n      let headGeoBot = new this.THREE.CylinderGeometry(bottomRadius, bottomRadius, botHeight, radialSegments);\n      headGeoTop.isTypeFiveTop = true;\n      headGeoBot.isTypeSixBottom = true;\n      headGeoTop.translate(0, botHeight + topHeight / 2, 0);\n      headGeoBot.translate(0, botHeight / 2, 0);\n      return [headGeoTop, headGeoBot];\n    }\n\n    getFastenerHeadGeoPolyWithoutWasher(wrenchSize, numOfEdges, height) {\n      wrenchSize /= 2;\n      let angle = (numOfEdges - 2) * 180 / numOfEdges / 2;\n      angle *= Math.PI / 180;\n      let radius = wrenchSize / Math.sin(angle);\n      let headGeo = new this.THREE.CylinderGeometry(radius, radius, height, numOfEdges);\n      headGeo.rotateY(angle / 2);\n      headGeo.translate(0, height / 2, 0);\n      headGeo.isPolygon = true;\n      return headGeo;\n    }\n\n    getFastenerHeadGeoPolyWithWasher(wrenchSize, numOfEdges, height, heightFactor, topRadius) {\n      wrenchSize /= 2;\n      let angle = (numOfEdges - 2) * 180 / numOfEdges / 2;\n      angle *= Math.PI / 180;\n      let radius = wrenchSize / Math.sin(angle);\n      let botHeight = height * heightFactor;\n      let topHeight = height - botHeight;\n      let headGeoTop = new this.THREE.CylinderGeometry(radius, radius, topHeight, numOfEdges);\n      headGeoTop.rotateY(angle / 2);\n      headGeoTop.translate(0, topHeight / 2 + botHeight, 0);\n      headGeoTop.isPolygon = true;\n      let headGeoBot = new this.THREE.CylinderGeometry(topRadius, topRadius, botHeight, 32);\n      headGeoBot.translate(0, botHeight / 2, 0);\n      return [headGeoTop, headGeoBot];\n    }\n\n    makeHeadWireframe(geometry, lineProps, drawBottomFrameHead = true) {\n      let wireframes = [];\n\n      if (geometry) {\n        if (geometry.length > 0) {\n          geometry.forEach(geo => {\n            let newWireframes = this.makeHeadWireframe(geo, lineProps, drawBottomFrameHead);\n            wireframes.push(...newWireframes);\n          });\n        } else {\n          if (geometry.type == \"CylinderGeometry\") {\n            let drawTopFrame = true;\n            let drawBotFrame = drawBottomFrameHead;\n            if (geometry.isTypeSixBottom) drawTopFrame = false;\n            if (geometry.isAddon) drawBotFrame = true;\n            if (geometry.isTypeSixTop) drawBotFrame = false;\n            if (geometry.isTypeFiveBottom) drawTopFrame = false;\n            if (geometry.isTypeFiveTop) drawBotFrame = false;\n            let drawEdges = geometry.isPolygon ? true : false;\n            let topBotWireframes = this.drawDoublesideFrame(geometry, lineProps, drawTopFrame, drawBotFrame, drawEdges);\n            wireframes.push(...topBotWireframes);\n          }\n        }\n      }\n\n      return wireframes;\n    }\n\n    getFastenerHeadGeo(headData) {\n      if (headData) {\n        let RADIAL_SEGMENTS = 32;\n        let headType = headData.type;\n        let topDiameter = headData.topDiameter.value;\n        let topDiameterFactor = headData.topDiameter.factor;\n        let bottomDiameter = headData.bottomDiameter.value;\n        let bottomDiameterFactor = headData.bottomDiameter.factor;\n        let topRadius = topDiameter / 2;\n        let bottomRadius = bottomDiameter / 2;\n        let height = headData.height.value;\n        let heightFactor = headData.height.factor;\n        let wrenchSize = headData.wrenchSize;\n        let numOfEdges = headData.numberOfEdges;\n        let headGeo;\n        let headGeoTop, headGeoBot;\n\n        if (headType == 1) {\n          if (topRadius == 0) topRadius = 0.001;\n          if (bottomRadius == 0) bottomRadius = 0.001;\n          headGeo = this.getFastenerHeadGeoCountersunk(topRadius, bottomRadius, height, RADIAL_SEGMENTS);\n        } else if (headType == 2) {\n          headGeo = this.getFastenerHeadGeoCylinder(topRadius, height, RADIAL_SEGMENTS);\n        } else if (headType == 3) {\n          [headGeoTop, headGeoBot] = this.getFastenerHeadGeoLentil(topRadius, height, heightFactor, RADIAL_SEGMENTS);\n          headGeo = [headGeoTop, headGeoBot];\n        } else if (headType == 4) {\n          headGeo = this.getFastenerHeadGeoDiskFlat(topRadius, height, RADIAL_SEGMENTS);\n        } else if (headType == 5) {\n          [headGeoTop, headGeoBot] = this.getFastenerHeadGeoDiskBottomFlat(topRadius, bottomRadius, topDiameterFactor, topDiameter, height, heightFactor, RADIAL_SEGMENTS);\n          headGeo = [headGeoTop, headGeoBot];\n        } else if (headType == 6) {\n          let topHeight = height * (1 - heightFactor);\n          let botHeight = height * heightFactor;\n          headGeoTop = new this.THREE.CylinderGeometry(topRadius, topRadius, topHeight, 32);\n          headGeoTop.isTypeSixTop = true;\n          headGeoBot = new this.THREE.CylinderGeometry((bottomDiameter + 2 * bottomDiameterFactor * bottomDiameter) / 2, bottomRadius, botHeight, RADIAL_SEGMENTS);\n          headGeoBot.isTypeSixBottom = true;\n          headGeoTop.translate(0, -topHeight / 2, 0);\n          headGeoBot.translate(0, -topHeight - botHeight / 2, 0);\n          headGeo = [headGeoTop, headGeoBot];\n        } else if (headType == 7) {\n          headGeo = this.getFastenerHeadGeoPolyWithoutWasher(wrenchSize, numOfEdges, height);\n        } else if (headType == 8) {\n          [headGeoTop, headGeoBot] = this.getFastenerHeadGeoPolyWithWasher(wrenchSize, numOfEdges, height, heightFactor, topRadius);\n          headGeo = [headGeoTop, headGeoBot];\n        }\n\n        return headGeo;\n      }\n    }\n    /**\n     * Shank Types\n     * 1: Circle\n     * 2: Square\n     */\n\n\n    getFastenerShankGeo(segments, shankData, fastener) {\n      let geometries = [];\n\n      if (shankData) {\n        let diameter = shankData.size;\n        segments.forEach(segment => {\n          let length = segment[1] - segment[0];\n          let newGeo;\n          if (shankData.type == 1) newGeo = new this.THREE.CylinderGeometry(diameter / 2, diameter / 2, length, 32);else if (shankData.type == 2) newGeo = new this.THREE.BoxGeometry(diameter, length, diameter);else console.log(\"Shank type is undefined\");\n\n          if (newGeo) {\n            if (segment[2]) newGeo.isTipSide = true;\n            newGeo.translate(0, -length / 2 - segment[0], 0);\n            geometries.push(newGeo);\n          }\n        });\n      } else {\n        geometries = null;\n      }\n\n      return geometries;\n    }\n\n    makeTipWireframe(tipData, geometry, lineProps, drawTopTip = true, drawBotTip = true, drawEdgesTip = false) {\n      // TODO: Refactor/Clean code.\n      let wireframes = [];\n\n      if (tipData.type == 1) {\n        let geoVertices = [...geometry.vertices];\n        geoVertices.splice(geoVertices.length - 2, 2);\n\n        if (drawTopTip) {\n          let wireframe = this.drawLineFromPoints(geoVertices, lineProps, true);\n          wireframes.push([wireframe]);\n        }\n      } else if (tipData.type == 2) {\n        if (geometry.parameters.radiusBottom) {\n          wireframes = this.drawDoublesideFrame(geometry, lineProps, drawTopTip);\n        } else {\n          let geoVertices = [...geometry.vertices];\n          geoVertices.splice(geoVertices.length - 2, 2);\n          let wireframe = this.drawLineFromPoints(geoVertices, lineProps, true);\n          wireframes.push([wireframe]);\n        }\n      } else if (tipData.type == 3) {\n        let depth = geometry.parameters.options.depth;\n        let partOne = [...geometry.vertices].splice(0, 3);\n        let partTwo = [];\n        partOne.forEach(vertex => partTwo.push(vertex.clone()));\n        partTwo.forEach(vertex => vertex.setComponent(2, vertex.z + depth));\n        let wireframesOne = this.drawLineFromPoints(partOne, lineProps, drawTopTip ? true : false);\n        wireframes.push([wireframesOne]);\n        let wireframesTwo = this.drawLineFromPoints(partTwo, lineProps, drawTopTip ? true : false);\n        wireframes.push([wireframesTwo]);\n\n        if (drawTopTip) {\n          let edgesLineArr = [];\n\n          for (let i = 0; i < partOne.length; i++) {\n            let newLine = this.drawLineFromPoints([partOne[i], partTwo[i]], lineProps);\n            edgesLineArr.push(newLine);\n          }\n\n          wireframes.push(edgesLineArr);\n        } else {\n          let edgesLineArr = [];\n          let newLine = this.drawLineFromPoints([partOne[1], partTwo[1]], lineProps);\n          edgesLineArr.push(newLine);\n          wireframes.push(edgesLineArr);\n        }\n      } else if (tipData.type == 4) {\n        let depth = geometry.parameters.options.depth;\n        let partOne = [];\n\n        if (geometry.vertices[3].z > 0) {\n          partOne = [...geometry.vertices].splice(0, 3);\n        } else {\n          partOne = [...geometry.vertices].splice(0, 4);\n        }\n\n        let partTwo = [];\n        partOne.forEach(vertex => partTwo.push(vertex.clone()));\n        partTwo.forEach(vertex => vertex.setComponent(2, vertex.z + depth));\n        let wireframesOne = this.drawLineFromPoints(partOne, lineProps, drawTopTip ? true : false);\n        wireframes.push([wireframesOne]);\n        let wireframesTwo = this.drawLineFromPoints(partTwo, lineProps, drawTopTip ? true : false);\n        wireframes.push([wireframesTwo]);\n\n        if (drawTopTip) {\n          let edgesLineArr = [];\n\n          for (let i = 0; i < partOne.length; i++) {\n            let newLine = this.drawLineFromPoints([partOne[i], partTwo[i]], lineProps);\n            edgesLineArr.push(newLine);\n          }\n\n          wireframes.push(edgesLineArr);\n        } else {\n          let edgesLineArr = [];\n\n          for (let i = 1; i < partOne.length - 1; i++) {\n            let newLine = this.drawLineFromPoints([partOne[i], partTwo[i]], lineProps);\n            edgesLineArr.push(newLine);\n          }\n\n          wireframes.push(edgesLineArr);\n        }\n      } else if (tipData.type == 5) {\n        let geoVertices = [...geometry.vertices].splice(0, 4);\n\n        if (drawTopTip) {\n          let wireframe = this.drawLineFromPoints(geoVertices, lineProps, true);\n          wireframes.push([wireframe]);\n        }\n\n        let pointVertex = geometry.vertices[4];\n        let pointArr = [];\n        geoVertices.forEach(vertex => {\n          let newLine = this.drawLineFromPoints([pointVertex, vertex], lineProps);\n          pointArr.push(newLine);\n        });\n        wireframes.push(pointArr);\n      } else if (tipData.type == 6) {\n        if (geometry.parameters.radiusBottom) {\n          wireframes = this.drawDoublesideFrame(geometry, lineProps, drawTopTip, true, true);\n        } else {\n          let geoVertices = [...geometry.vertices];\n          geoVertices.splice(geoVertices.length - 2, 2);\n          let pointVertex = geometry.vertices[4];\n          let pointArr = [];\n          geoVertices.forEach(vertex => {\n            let newLine = this.drawLineFromPoints([pointVertex, vertex], lineProps);\n            pointArr.push(newLine);\n          });\n          wireframes.push(pointArr);\n\n          if (drawTopTip) {\n            let wireframe = this.drawLineFromPoints(geoVertices, lineProps, true);\n            wireframes.push([wireframe]);\n          }\n        }\n      }\n\n      return wireframes;\n    }\n    /**\n     * Tip Types\n     * 1: Circle Pointed\n     * 2: Circle Blunt\n     * 3: Square Half Pointed\n     * 4: Square Half Blunt\n     * 5: Square Full Pointed\n     * 6: Square Full Blunt\n     */\n\n\n    getFastenerTipGeo(tipData, tipDiameter, fastener, axisLength) {\n      let tipGeo;\n      let height = tipData ? tipData.height : 0;\n      let tipRadius = tipDiameter / 2;\n\n      if (height > 0) {\n        if (tipData.type == 1) {\n          tipGeo = new this.THREE.CylinderGeometry(tipRadius, 0, height, 32);\n        } else if (tipData.type == 2) {\n          let bottomRadius = tipRadius - height;\n          if (bottomRadius < 0) bottomRadius = 0;\n          tipGeo = new this.THREE.CylinderGeometry(tipRadius, bottomRadius, height, 32);\n        } else if (tipData.type == 3) {\n          let shape = new this.THREE.Shape();\n          shape.moveTo(0, -height / 2);\n          shape.lineTo(tipRadius, height / 2);\n          shape.lineTo(-tipRadius, height / 2);\n          shape.lineTo(0, -height / 2);\n          let extrudeSettings = {\n            steps: 32,\n            depth: 2 * tipRadius,\n            bevelEnabled: false\n          };\n          tipGeo = new this.THREE.ExtrudeGeometry(shape, extrudeSettings);\n          tipGeo.translate(0, 0, -fastener.components.shank.size / 2);\n        } else if (tipData.type == 4) {\n          let bottomRadius = (tipDiameter - 2 * height) / 2;\n          if (bottomRadius < 0) bottomRadius = 0;\n          let shape = new this.THREE.Shape();\n          shape.moveTo(bottomRadius, -height / 2);\n          shape.lineTo(tipRadius, height / 2);\n          shape.lineTo(-tipRadius, height / 2);\n          shape.lineTo(-bottomRadius, -height / 2);\n          shape.lineTo(bottomRadius, -height / 2);\n          let extrudeSettings = {\n            steps: 32,\n            depth: 2 * tipRadius,\n            bevelEnabled: false\n          };\n          tipGeo = new this.THREE.ExtrudeGeometry(shape, extrudeSettings);\n          tipGeo.translate(0, 0, -fastener.components.shank.size / 2);\n        } else if (tipData.type == 5) {\n          tipRadius = Math.sqrt(2 * Math.pow(tipDiameter, 2)) / 2;\n          tipGeo = new this.THREE.CylinderGeometry(tipRadius, 0, height, 4);\n          tipGeo.rotateY(Math.PI / 4);\n        } else if (tipData.type == 6) {\n          let topRadius = Math.sqrt(2 * Math.pow(tipRadius, 2));\n          let correctedRadius = tipRadius - height > 0 ? tipRadius - height : 0;\n          let bottomRadius = Math.sqrt(2 * Math.pow(correctedRadius, 2));\n          tipGeo = new this.THREE.CylinderGeometry(topRadius, bottomRadius, height, 4);\n          tipGeo.rotateY(Math.PI / 4);\n        } else {\n          tipGeo = null;\n        }\n      } else {\n        tipGeo = null;\n      }\n\n      if (tipGeo) {\n        tipGeo.computeBoundingBox();\n        tipGeo.center();\n        tipGeo.translate(0, height / 2 - axisLength, 0);\n      }\n\n      return tipGeo;\n    }\n    /**\n     * Thread Types\n     * 1: with pitch\n     * 2: without pitch\n     */\n\n\n    getSpiralAndCylGeo(threadSegments, fastenerProps) {\n      let cylGeometries = [];\n      let spiralGeometries = [];\n      let wireframePoints = [];\n      let cylWireframes = [];\n      threadSegments.forEach(segment => {\n        let threadData = segment[2];\n\n        if (threadData.pitch > 0) {\n          let threadDiameter = threadData.threadDiameter;\n          let coreDiameter = threadData.coreDiameter;\n          let pitch = threadData.pitch;\n          let height = threadData.height;\n          let length = segment[1] - segment[0];\n\n          if (threadDiameter && length > 0 && threadDiameter > coreDiameter) {\n            let spiral = new Spiral(coreDiameter / 2, length, pitch, (threadDiameter - coreDiameter) / 2, height, new this.THREE.MeshBasicMaterial(), this);\n            let cylGeo = spiral.getCylGeo();\n            let [spiralGeo, newWireframePoints] = spiral.getSpiralGeo();\n            wireframePoints.push(newWireframePoints);\n            cylGeo.translate(0, -segment[0], 0);\n            spiralGeo.translate(0, -segment[0], 0); ///\n            // let lineProps = fastenerProps.fastener.headSide.line;\n            // let cylWireframe = this.makeHeadWireframe(cylGeo, lineProps);\n            // cylWireframes.push(cylWireframe);\n            ///\n\n            cylGeometries.push(cylGeo);\n            spiralGeometries.push(spiralGeo);\n          }\n        }\n      });\n      let firstCyl, firstSpiral;\n\n      if (cylGeometries.length > 0 && spiralGeometries.length > 0) {\n        firstCyl = cylGeometries.splice(0, 1)[0];\n        cylGeometries.forEach(geo => firstCyl.merge(geo));\n        firstSpiral = spiralGeometries.splice(0, 1)[0];\n        spiralGeometries.forEach(geo => firstSpiral.merge(geo));\n      }\n\n      return [firstCyl, firstSpiral, wireframePoints, cylWireframes];\n    }\n\n    getThreadWithoutPitchGeo(threadSegments, fastenerProps) {\n      let geometries = [];\n      let wireframePoints = [];\n      let coreGeometries = [];\n      let coreWireframes = [];\n      threadSegments.forEach(segment => {\n        let insertionDistance = segment[0];\n        let length = segment[1] - segment[0];\n        let threadsData = segment[2];\n        let coreRadius = threadsData.coreDiameter / 2;\n        let threadRadius = threadsData.threadDiameter / 2;\n        let height = threadsData.height;\n        let distance = threadsData.distance;\n        let midGeoHeight = distance - height;\n        let threadPartHeight = height / 2; // top and bot geometry height\n\n        let pitch = threadsData.pitch;\n        if (threadPartHeight == 0) threadPartHeight = 0.001;\n        if (midGeoHeight == 0) midGeoHeight = 0.001;\n\n        if (pitch == 0 && length > 0 && (threadPartHeight > 0 || midGeoHeight > 0) && threadRadius > 0 && coreRadius >= 0 && threadRadius > coreRadius) {\n          if (coreRadius == 0) coreRadius = 0.01;\n          if (threadRadius == 0) threadRadius = 0.01;\n          let coreGeo = new this.THREE.CylinderGeometry(coreRadius, coreRadius, length, 32);\n          coreGeo.translate(0, -length / 2 - insertionDistance, 0); ///\n          // let lineProps = fastenerProps.fastener.headSide.line;\n          // let coreWireframe = this.makeHeadWireframe(coreGeo, lineProps);\n          // coreWireframes.push(coreWireframe);\n          ///\n\n          coreGeometries.push(coreGeo);\n          let wireframePointsOuter = [];\n          let wireframePointsInner = [];\n          let startAngle = 0;\n          let endAngle = 2 * Math.PI;\n          let step = endAngle / 32;\n\n          while (startAngle < endAngle) {\n            let widthCoeff = Math.cos(startAngle);\n            let depthCoeff = Math.sin(startAngle);\n            let outerPoint = new this.THREE.Vector3(threadRadius * widthCoeff, 0, threadRadius * depthCoeff);\n            let innerPoint = new this.THREE.Vector3(coreRadius * widthCoeff, 0, coreRadius * depthCoeff);\n            startAngle += step;\n            wireframePointsOuter.push(outerPoint);\n            wireframePointsInner.push(innerPoint);\n          }\n          /*\n            turns\n            0: topGeo\n            1: botGeo\n            2: midGeo\n          */\n\n\n          let turn = 0;\n          let distanceToLoop = segment[0] + length;\n\n          while (insertionDistance < distanceToLoop) {\n            if (turn == 0) {\n              if (threadPartHeight > 0) {\n                let topGeo = new this.THREE.CylinderGeometry(coreRadius, threadRadius, threadPartHeight, 32, 1, true);\n                topGeo.translate(0, -threadPartHeight / 2 - insertionDistance, 0); ///\n\n                let wireframeNewPoints = [...wireframePointsInner].map(point => point = point.clone().setComponent(1, -insertionDistance));\n                wireframePoints.push(wireframeNewPoints);\n                let wireframeNewPointsOuter = [...wireframePointsOuter].map(point => point = point.clone().setComponent(1, -insertionDistance - threadPartHeight));\n                wireframePoints.push(wireframeNewPointsOuter); ///\n\n                insertionDistance += threadPartHeight;\n                geometries.push(topGeo);\n              }\n            } else if (turn == 1) {\n              if (threadPartHeight > 0) {\n                let botGeo = new this.THREE.CylinderGeometry(threadRadius, coreRadius, threadPartHeight, 32, 1, true);\n                botGeo.translate(0, -threadPartHeight / 2 - insertionDistance, 0); ///\n\n                let wireframeNewPoints = [...wireframePointsInner].map(point => point = point.clone().setComponent(1, -insertionDistance - threadPartHeight));\n                wireframePoints.push(wireframeNewPoints); ///\n\n                insertionDistance += threadPartHeight;\n                geometries.push(botGeo);\n              }\n            } else {\n              if (midGeoHeight > 0) {\n                // let midGeo = new this.THREE.CylinderGeometry(coreRadius, coreRadius, midGeoHeight, 32, 1, true);\n                // midGeo.translate(0, -midGeoHeight/2 - insertionDistance, 0);\n                // geometries.push(midGeo);\n                insertionDistance += midGeoHeight;\n              }\n            }\n\n            turn++;\n            if (turn > 2) turn = 0;\n          }\n        }\n      });\n      let geometry = geometries.splice(0, 1)[0];\n      geometries.forEach(geo => geometry.merge(geo));\n      let coreGeometry = coreGeometries.splice(0, 1)[0];\n      coreGeometries.forEach(geo => coreGeometry.merge(geo));\n      return [geometry, coreGeometry, wireframePoints, coreWireframes];\n    }\n\n    drawFastenerHead_1_Countersunk(headGeo, fastenerMaterial, headData) {\n      let head;\n\n      if (headData.height.value > 0 && (headData.topDiameter.value > 0 || headData.bottomDiameter.value > 0)) {\n        head = new this.THREE.Mesh(headGeo, fastenerMaterial);\n      } else if (headData.type == 2 && headData.topDiameter.value > 0 && headData.height.value > 0) {\n        head = new this.THREE.Mesh(headGeo, fastenerMaterial);\n      } else {\n        head = null;\n      }\n\n      return head;\n    }\n\n    drawFastenerHead_4_DiscFlat(geometry, material, headData) {\n      let cylinder;\n\n      if (headData.topDiameter.value > 0 && headData.height.value > 0) {\n        cylinder = new this.THREE.Mesh(geometry, material);\n      } else {\n        cylinder = null;\n      }\n\n      return cylinder;\n    }\n\n    drawFastenerHead_7_PolygonWithoutWasher(geometry, material, headData) {\n      let hexagonMesh;\n\n      if (headData.height.value > 0 && headData.wrenchSize > 0 && headData.numberOfEdges > 2) {\n        hexagonMesh = new this.THREE.Mesh(geometry, material);\n      } else {\n        hexagonMesh = null;\n      }\n\n      return hexagonMesh;\n    }\n\n    drawFastenerHead_8_PolygonWithWasher(geometry, material, headData) {\n      let polyWithWasher;\n\n      if (headData.topDiameter.value > 0 && headData.height.value > 0 && headData.height.factor > 0 && headData.height.factor < 1 && headData.wrenchSize > 0 && headData.wrenchSize < headData.topDiameter.value && headData.numberOfEdges > 2) {\n        let [hexExtr, cylGeo] = geometry;\n        let hexagonMesh = new this.THREE.Mesh(hexExtr, material);\n        let cylinder = new this.THREE.Mesh(cylGeo, material);\n        let hexagonCSG = this.CSG.fromMesh(hexagonMesh);\n        let cylinderMesh = this.CSG.fromMesh(cylinder);\n        let unionCSG = hexagonCSG.union(cylinderMesh);\n        polyWithWasher = this.CSG.toMesh(unionCSG, new this.THREE.Matrix4());\n        polyWithWasher.material = material;\n      } else {\n        polyWithWasher = null;\n      }\n\n      return polyWithWasher;\n    }\n\n    drawFastenerHead_5_DiscBottomFlat(geometry, material, headData) {\n      let discBottomFlat;\n\n      if (headData.topDiameter.value > 0 && headData.topDiameter.factor > 0 && 2 * (headData.topDiameter.factor * headData.topDiameter.value) + headData.topDiameter.value < headData.bottomDiameter.value && headData.bottomDiameter.value > 0 && headData.height.value > 0 && headData.height.factor > 0 && headData.height.factor < 1) {\n        let [geometry1, geometry2] = geometry;\n        let cylinderMesh = new this.THREE.Mesh(geometry1, material);\n        let cylinder = new this.THREE.Mesh(geometry2, material);\n        let csgOne = this.CSG.fromMesh(cylinderMesh);\n        let csgTwo = this.CSG.fromMesh(cylinder);\n        let unionCSG = csgOne.union(csgTwo);\n        discBottomFlat = this.CSG.toMesh(unionCSG, new this.THREE.Matrix4());\n        discBottomFlat.material = material;\n      } else {\n        discBottomFlat = null;\n      }\n\n      return discBottomFlat;\n    }\n\n    drawFastenerHead_6_DiscTopFlat(geometry, material, headData) {\n      let diskTopFlat;\n\n      if (headData.topDiameter.value > 0 && headData.bottomDiameter.value > 0 && headData.bottomDiameter.factor > 0 && 2 * (headData.bottomDiameter.factor * headData.bottomDiameter.value) + headData.bottomDiameter.value < headData.topDiameter.value && headData.height.value > 0 && headData.height.factor > 0 && headData.height.factor < 1) {\n        let [geometry1, geometry2] = geometry;\n        let cylinder = new this.THREE.Mesh(geometry1, material);\n        let cylinderMesh = new this.THREE.Mesh(geometry2, material);\n        let csgOne = this.CSG.fromMesh(cylinder);\n        let csgTwo = this.CSG.fromMesh(cylinderMesh);\n        let unionCSG = csgOne.union(csgTwo);\n        diskTopFlat = this.CSG.toMesh(unionCSG, new this.THREE.Matrix4());\n        diskTopFlat.material = material;\n      } else {\n        diskTopFlat = null;\n      }\n\n      return diskTopFlat;\n    }\n\n    drawFastenerHead_3_Lentil(geometry, material, headData) {\n      let lentilHead;\n\n      if (headData.topDiameter.value > 0 && headData.height.value > 0 && headData.height.factor > 0 && headData.height.factor < 1) {\n        let [ellipsoidGeo, cylinderGeo] = geometry;\n        let eraserGeo = new this.THREE.BoxGeometry(headData.topDiameter.value, headData.height.value, headData.topDiameter.value);\n        eraserGeo.translate(0, -headData.height.value / 2, 0);\n        let eraserMesh = new this.THREE.Mesh(eraserGeo);\n        var ellipsoidmesh = new this.THREE.Mesh(ellipsoidGeo);\n        var cylinder = new this.THREE.Mesh(cylinderGeo);\n        let eraserCSG = this.CSG.fromMesh(eraserMesh);\n        let ellipseCSG = this.CSG.fromMesh(ellipsoidmesh).subtract(eraserCSG);\n        let cylinderCSG = this.CSG.fromMesh(cylinder);\n        let lentilHeadCSG = ellipseCSG.union(cylinderCSG);\n        lentilHead = this.CSG.toMesh(lentilHeadCSG, new this.THREE.Matrix4());\n        lentilHead.material = material;\n      } else {\n        lentilHead = null;\n      }\n\n      return lentilHead;\n    }\n\n    drawFastenerShank(shank, properties, shankGeo, drawTopFrameShank = true, drawBotFrameShank = true) {\n      let shanks = {\n        headSide: [],\n        tipSide: []\n      };\n      let shankWireframes = [];\n      let tipSideProps = properties.fastener.tipSide;\n      let linePropsHeadSide = properties.fastener.headSide.line;\n      let lineProps = tipSideProps && shank.tipSideLength ? tipSideProps.line : linePropsHeadSide;\n      let drawEdges = shank && shank.type === 2 ? true : false;\n\n      if (shankGeo && shank.size > 0) {\n        shankGeo.forEach(geo => {\n          if (geo.isTipSide) drawTopFrameShank = false;\n          let newWireframe = this.drawDoublesideFrame(geo, lineProps, drawTopFrameShank, drawBotFrameShank, drawEdges);\n          shankWireframes.push(...newWireframe);\n          let shankMesh = new this.THREE.Mesh(geo);\n          if (geo.isTipSide) shanks.tipSide.push(shankMesh);else shanks.headSide.push(shankMesh);\n        });\n      }\n\n      return [shanks, shankWireframes];\n    } // TODO: add wireframe\n\n\n    drawFastenerThread_0_WithPitch(cylGeo, spiralGeo, fastenerMaterial, wireframePoints, lineProps, lineMaterial) {\n      let spiralMesh, cylMesh;\n\n      if (cylGeo && spiralGeo) {\n        spiralMesh = new this.THREE.Mesh(spiralGeo, fastenerMaterial.clone());\n        spiralMesh.material.side = this.THREE.DoubleSide;\n        cylMesh = new this.THREE.Mesh(cylGeo, fastenerMaterial);\n        wireframePoints.forEach(pointArr => {\n          pointArr.forEach(points => {\n            let wireframe = this.drawLineFromPoints(points, lineProps);\n            spiralMesh.add(wireframe);\n          });\n          let endPointsOne = [pointArr[0][0], pointArr[1][0], pointArr[2][0]];\n          let endWireframeOne = this.drawLineFromPoints(endPointsOne, lineProps);\n          spiralMesh.add(endWireframeOne);\n          let endPointsTwo = [pointArr[0][pointArr[0].length - 1], pointArr[1][pointArr[0].length - 1], pointArr[2][pointArr[0].length - 1]];\n          let endWireframeTwo = this.drawLineFromPoints(endPointsTwo, lineProps);\n          spiralMesh.add(endWireframeTwo);\n        });\n      } else {\n        spiralMesh = null;\n        cylMesh = null;\n      }\n\n      return [cylMesh, spiralMesh];\n    } // TODO: apply wireframe\n\n\n    drawFastenerThread_1_WithoutPitch(threadGeo, coreGeo, material, wireframePoints, lineProps) {\n      let thread;\n      if (threadGeo) thread = new this.THREE.Mesh(threadGeo, material.clone());else thread = null;\n      let core;\n      if (coreGeo) core = new this.THREE.Mesh(coreGeo);else core = null;\n\n      if (thread) {\n        thread.material.side = this.THREE.DoubleSide;\n        wireframePoints.forEach(points => {\n          let wireframe = this.drawLineFromPoints(points, lineProps, true);\n          thread.add(wireframe);\n        });\n      }\n\n      return [thread, core];\n    }\n\n    drawFastenerTip(tipGeo, fastenerMaterial, tipSideMaterial) {\n      let cylinder;\n\n      if (tipGeo && fastenerMaterial) {\n        cylinder = new this.THREE.Mesh(tipGeo);\n        if (tipSideMaterial) cylinder.isTipSide = true;\n      } else {\n        cylinder = null;\n      }\n\n      return cylinder;\n    }\n\n    drawLineFromPoints(points, props, isClosed = false) {\n      if (props.color.alpha == 0) {\n        let line = new this.THREE.Mesh(); // TODO: might need better solution\n\n        return line;\n      }\n\n      let colorValues = {\n        red: props.color.red,\n        green: props.color.green,\n        blue: props.color.blue\n      };\n      let addToColor = 20;\n      colorValues.red = colorValues.red + addToColor <= 255 ? colorValues.red + addToColor : Math.min(colorValues.red + addToColor, 255);\n      colorValues.green = colorValues.green + addToColor <= 255 ? colorValues.green + addToColor : Math.min(colorValues.green + addToColor, 255);\n      colorValues.blue = colorValues.blue + addToColor <= 255 ? colorValues.blue + addToColor : Math.min(colorValues.blue + addToColor, 255);\n      let lineColor = \"rgb(\" + colorValues.red + \", \" + colorValues.green + \", \" + colorValues.blue + \")\";\n      let material = new this.THREE.LineBasicMaterial({\n        color: lineColor\n      });\n      let geometry = new this.THREE.BufferGeometry().setFromPoints(points);\n      let line;\n      if (isClosed) line = new this.THREE.LineLoop(geometry, material);else line = new this.THREE.Line(geometry, material);\n      return line;\n    }\n\n    rotateObject(object, direction, directionTwo) {\n      let normalVector = new this.THREE.Vector3().crossVectors(direction, directionTwo);\n      let directionVector = new this.THREE.Vector3(directionTwo.x, directionTwo.y, directionTwo.z);\n      let newUpVector = new this.THREE.Vector3().crossVectors(normalVector, directionVector);\n      let dotProduct = object.up.dot(newUpVector);\n      let rotationAngle = -Math.acos(dotProduct); // by default THREE.js rotates counterclockwise, so I switched sign (correct?)\n\n      object.rotateOnAxis(normalVector, rotationAngle);\n      object.up = newUpVector;\n      object.lookAt(object.position.clone().add(normalVector));\n      return object;\n    }\n\n    setTime(meshArray, i, a) {\n      var drawnObject = new Object();\n      drawnObject.id = this.GraphicsThree3D.jsonData.fasteners[i].id;\n      drawnObject.type = \"fastener\";\n      drawnObject.data = this.GraphicsThree3D.jsonData;\n      drawnObject.sceneObject = meshArray[a];\n      this.GraphicsThree3D.ThreeObjects.push(drawnObject);\n      this.GraphicsThree3D.scene.add(drawnObject.sceneObject);\n    }\n\n    drawClamp(fastener) {\n      let tipDiameter = fastener.components.threads ? fastener.components.threads[0].coreDiameter : fastener.components.shank.size;\n      let tipGeo = this.getFastenerTipGeo(fastener.components.tip, tipDiameter, fastener, fastener.components.axis.length);\n\n      for (let b = 0; b < fastener.insertionPoints.length; b++) {\n        let insertionPoint = fastener.insertionPoints[b].insertionPoint;\n        let rotationVector = this.utils.normalizeVector(fastener.insertionPoints[b].directionVector1);\n        let rotationVectorTwo = this.utils.normalizeVector(fastener.insertionPoints[b].directionVector2);\n        let headSideMeshes = [];\n        let tipSideMeshes = [];\n        let [head, headWireframes] = this.drawClampHeadStapleSpine(fastener.components.shank, fastener.properties);\n        if (head) headSideMeshes.push(head);\n        let [leftAxisBot, leftAxisTop, axisWireframes] = this.drawClampAxis(fastener.components.axis, fastener.components.shank, fastener.components.tip, fastener.properties, true);\n        let [rightAxisBot, rightAxisTop, axisWireframesRight] = this.drawClampAxis(fastener.components.axis, fastener.components.shank, fastener.components.tip, fastener.properties, false);\n\n        if (fastener.properties.fastener.tipSide) {\n          if (leftAxisTop) headSideMeshes.push(leftAxisTop);\n          if (rightAxisTop) headSideMeshes.push(rightAxisTop);\n          if (leftAxisBot) tipSideMeshes.push(leftAxisBot);\n          if (rightAxisBot) tipSideMeshes.push(rightAxisBot);\n        } else {\n          if (leftAxisBot) headSideMeshes.push(leftAxisBot);\n          if (rightAxisBot) headSideMeshes.push(rightAxisBot);\n        }\n\n        let [tipLeft, tipWireframes] = this.drawClampTip(fastener.components.shank, fastener.properties, fastener.components.tip, true, tipGeo);\n        let [tipRight, tipWireframesRight] = this.drawClampTip(fastener.components.shank, fastener.properties, fastener.components.tip, false, tipGeo);\n\n        if (fastener.properties.fastener.tipSide) {\n          if (tipLeft) tipSideMeshes.push(tipLeft);\n          if (tipRight) tipSideMeshes.push(tipRight);\n        } else {\n          if (tipLeft) headSideMeshes.push(tipLeft);\n          if (tipRight) headSideMeshes.push(tipRight);\n        }\n\n        let headSideMesh, tipSideMesh;\n\n        if (fastener.properties.fastener.headSide) {\n          let headSideMaterial = this.getMaterial(fastener.properties, \"headSide\");\n          headSideMaterial.side = this.THREE.FrontSide;\n\n          if (headSideMeshes.length > 0) {\n            headSideMesh = headSideMeshes.splice(0, 1)[0];\n            headSideMesh.updateMatrix();\n            headSideMeshes.forEach(mesh => {\n              mesh.updateMatrix();\n              let firstCSG = this.CSG.fromMesh(headSideMesh);\n              let secondCSG = this.CSG.fromMesh(mesh);\n              let unionCSG = firstCSG.union(secondCSG);\n              let unionMesh = this.CSG.toMesh(unionCSG, new this.THREE.Matrix4());\n              headSideMesh = unionMesh;\n            });\n          }\n\n          headSideMesh.material = headSideMaterial;\n        }\n\n        if (fastener.properties.fastener.tipSide) {\n          let tipSideMaterial = this.getMaterial(fastener.properties, \"tipSide\");\n          tipSideMaterial.side = this.THREE.FrontSide;\n\n          if (tipSideMeshes.length > 0) {\n            tipSideMesh = tipSideMeshes.splice(0, 1)[0];\n            tipSideMesh.updateMatrix();\n            tipSideMeshes.forEach(mesh => {\n              mesh.updateMatrix();\n              let firstCSG = this.CSG.fromMesh(tipSideMesh);\n              let secondCSG = this.CSG.fromMesh(mesh);\n              let unionCSG = firstCSG.union(secondCSG);\n              let unionMesh = this.CSG.toMesh(unionCSG, new this.THREE.Matrix4());\n              tipSideMesh = unionMesh;\n            });\n          }\n\n          tipSideMesh.material = tipSideMaterial;\n        }\n\n        let fastenerClamp = new this.THREE.Object3D();\n\n        if (headSideMesh) {\n          headSideMesh.renderOrder = -4;\n          fastenerClamp.add(headSideMesh);\n        }\n\n        if (tipSideMesh) {\n          tipSideMesh.renderOrder = -4;\n          fastenerClamp.add(tipSideMesh);\n        }\n\n        let backSideHead, backSideTip;\n\n        if (headSideMesh) {\n          let geo = headSideMesh.geometry.clone();\n          let mat = headSideMesh.material.clone();\n          mat.side = this.THREE.BackSide;\n          backSideHead = new this.THREE.Mesh(geo, mat);\n          backSideHead.renderOrder = -5;\n          fastenerClamp.add(backSideHead);\n        }\n\n        if (tipSideMesh) {\n          let geo = tipSideMesh.geometry.clone();\n          let mat = tipSideMesh.material.clone();\n          mat.side = this.THREE.BackSide;\n          backSideTip = new this.THREE.Mesh(geo, mat);\n          backSideTip.renderOrder = -5;\n          fastenerClamp.add(backSideTip);\n        }\n\n        headWireframes.forEach(wireframe => wireframe.forEach(line => {\n          fastenerClamp.add(line);\n        }));\n        axisWireframes.forEach(wireframe => wireframe.forEach(line => {\n          fastenerClamp.add(line);\n        }));\n        axisWireframesRight.forEach(wireframe => wireframe.forEach(line => {\n          fastenerClamp.add(line);\n        }));\n        tipWireframes.forEach(wireframe => wireframe.forEach(line => {\n          fastenerClamp.add(line);\n        }));\n        tipWireframesRight.forEach(wireframe => wireframe.forEach(line => {\n          fastenerClamp.add(line);\n        })); ///\n        // Axis\n\n        let axisGeo, axisPointGeo;\n        let axisMat, axisPointMat;\n        let inversedDirection = false;\n\n        if (fastener.components.axis.length < 0) {\n          inversedDirection = true;\n          fastener.components.axis.length *= -1; // maybe change code not to modify json?\n        }\n\n        if (fastener.properties.axis && fastener.components.axis.length > 0) {\n          let lineProps = fastener.properties.axis.line;\n\n          if (lineProps.thickness && lineProps.type > 0) {\n            axisGeo = this.getAxisGeo(fastener.components.axis, fastener.properties.axis);\n            axisMat = this.GraphicsThree3D.getMaterialFromColor(lineProps.color);\n          }\n\n          let pointProps = fastener.properties.axis.point;\n          axisPointGeo = this.getAxisPointGeo(pointProps);\n          axisPointMat = this.GraphicsThree3D.getMaterialFromColor(pointProps.color);\n        }\n\n        let axis;\n        if (fastener.properties.axis) axis = this.drawAxis(axisGeo, axisPointGeo, axisMat, axisPointMat);\n        if (axis) fastenerClamp.add(axis); ///\n\n        let directionVector = new this.THREE.Vector3(rotationVector.x, rotationVector.y, rotationVector.z);\n        let directionVectorTwo = new this.THREE.Vector3(rotationVectorTwo.x, rotationVectorTwo.y, rotationVectorTwo.z);\n\n        if (inversedDirection) {\n          directionVector.negate();\n          directionVectorTwo.negate();\n        }\n\n        this.rotateObject(fastenerClamp, directionVector, directionVectorTwo);\n        fastenerClamp.position.set(insertionPoint.x, insertionPoint.y, insertionPoint.z); // this.addToDimChainCollisionDetection(fastenerClamp);\n\n        this.GraphicsThree3D.scene.add(fastenerClamp);\n        this.GraphicsThree3D.addObjectToVisControl(fastenerClamp, \"fastener\");\n      }\n    }\n\n    drawClampHeadStapleSpine(shank, propertiesData) {\n      const depth = shank.size;\n      const width = shank.offsetLength;\n      const height = shank.size;\n      let headWireframes = [];\n      let lineProps = propertiesData.fastener.headSide.line;\n      let material = this.getMaterial(propertiesData);\n\n      if (shank.type == 1) {\n        var geometry = new this.THREE.CylinderGeometry(depth / 2, depth / 2, width, 32);\n        geometry.translate(-depth / 2, 0, 0);\n      } else if (shank.type == 2) {\n        var geometry = new this.THREE.BoxGeometry(depth, height, width);\n        geometry.translate(0, -height / 2, 0);\n      } //\n\n\n      let cube; // TODO: remove duplicate code / clean code\n\n      let cubeGeoCSG;\n\n      if (shank.type == 1) {\n        let eraserBoxSize = Math.sqrt(2 * Math.pow(depth, 2));\n        let eraserBox = new this.THREE.Mesh(new this.THREE.BoxGeometry(eraserBoxSize, eraserBoxSize, eraserBoxSize));\n        eraserBox.rotation.z = Math.PI / 4;\n        eraserBox.position.set(-depth, width / 2, 0);\n        eraserBox.updateMatrix();\n        let geomesh = new this.THREE.Mesh(geometry);\n        let eraserCSG = this.GraphicsThree3D.CSG.fromMesh(eraserBox);\n        let geoCSG = this.GraphicsThree3D.CSG.fromMesh(geomesh);\n        cubeGeoCSG = geoCSG.subtract(eraserCSG);\n        eraserBox.position.set(-depth, -width / 2, 0);\n        eraserBox.updateMatrix();\n        eraserCSG = this.GraphicsThree3D.CSG.fromMesh(eraserBox);\n        cubeGeoCSG = cubeGeoCSG.subtract(eraserCSG);\n      } else if (shank.type == 2) {\n        let eraserBoxSize = Math.sqrt(2 * Math.pow(depth, 2));\n        let eraserBox = new this.THREE.Mesh(new this.THREE.BoxGeometry(eraserBoxSize, eraserBoxSize, eraserBoxSize));\n        eraserBox.rotation.x = Math.PI / 4;\n        eraserBox.position.set(0, -depth, width / 2);\n        eraserBox.updateMatrix();\n        let geomesh = new this.THREE.Mesh(geometry);\n        let eraserCSG = this.GraphicsThree3D.CSG.fromMesh(eraserBox);\n        let geoCSG = this.GraphicsThree3D.CSG.fromMesh(geomesh);\n        cubeGeoCSG = geoCSG.subtract(eraserCSG);\n        eraserBox.position.set(0, -depth, -width / 2);\n        eraserBox.updateMatrix();\n        eraserCSG = this.GraphicsThree3D.CSG.fromMesh(eraserBox);\n        cubeGeoCSG = cubeGeoCSG.subtract(eraserCSG);\n      }\n\n      cube = this.GraphicsThree3D.CSG.toMesh(cubeGeoCSG, new this.THREE.Matrix4());\n      cube.material = material;\n\n      if (geometry.type == \"CylinderGeometry\") {\n        cube.rotation.z = Math.PI / 2;\n        let radiusX = Math.sqrt(2 * Math.pow(depth / 2, 2));\n        let partOne = this.getEllipsePointsXZ(radiusX, depth / 2, Math.PI / 4, {\n          x: -width / 2 + depth / 2,\n          y: -depth / 2,\n          z: 0\n        });\n        let partTwo = this.getEllipsePointsXZ(radiusX, depth / 2, -Math.PI / 4, {\n          x: width / 2 - depth / 2,\n          y: -depth / 2,\n          z: 0\n        });\n        let wireframeOne = this.drawLineFromPoints(partOne, lineProps, true);\n        headWireframes.push([wireframeOne]);\n        let wireframeTwo = this.drawLineFromPoints(partTwo, lineProps, true);\n        headWireframes.push([wireframeTwo]);\n      } else if (geometry.type == \"BoxGeometry\") {\n        cube.rotation.y = Math.PI / 2;\n        let cubeWireframe = [];\n        let pointsOne = [new this.THREE.Vector3(-width / 2, 0, -depth / 2), new this.THREE.Vector3(-width / 2, 0, depth / 2), new this.THREE.Vector3(-width / 2 + depth, -depth, depth / 2), new this.THREE.Vector3(-width / 2 + depth, -depth, -depth / 2)];\n        let pointsTwo = [new this.THREE.Vector3(width / 2, 0, -depth / 2), new this.THREE.Vector3(width / 2, 0, depth / 2), new this.THREE.Vector3(width / 2 - depth, -depth, depth / 2), new this.THREE.Vector3(width / 2 - depth, -depth, -depth / 2)];\n\n        for (let i = 0; i < pointsOne.length; i++) {\n          let newLine = this.drawLineFromPoints([pointsOne[i], pointsTwo[i]], lineProps);\n          cubeWireframe.push(newLine);\n        }\n\n        headWireframes.push(cubeWireframe);\n        let edgePointsOne = [...pointsOne.slice(1, 3), ...pointsTwo.slice(1, 3)];\n        let edgePointsTwo = [pointsOne[0], pointsOne[3], pointsTwo[0], pointsTwo[3]];\n        let edgesLineArr = [];\n\n        for (let i = 0; i < edgePointsOne.length; i++) {\n          let newLine = this.drawLineFromPoints([edgePointsOne[i], edgePointsTwo[i]], lineProps);\n          edgesLineArr.push(newLine);\n        }\n\n        headWireframes.push(edgesLineArr);\n      }\n\n      return [cube, headWireframes];\n    }\n\n    drawClampAxis(axis, shank, tipData, propertiesData, isLeft) {\n      const depth = shank.size;\n      const width = shank.size;\n      let height = axis.length;\n      let axisWireframes = [];\n      let offsetFromCenter = isLeft ? -(shank.offsetLength / 2) : shank.offsetLength / 2;\n      let positiveOrNegative = Math.sign(offsetFromCenter);\n\n      if (tipData && tipData.type > 0) {\n        height -= tipData.height;\n      }\n\n      let lineProps = propertiesData.fastener.headSide.line;\n      let material = this.getMaterial(propertiesData);\n      let returnMeshes = [];\n      let geometry, geometryTwo;\n      let tipSideLength = shank.tipSideLength;\n\n      if (tipSideLength) {\n        height -= tipSideLength + 0.0001;\n\n        if (shank.type == 1) {\n          geometryTwo = new this.THREE.CylinderGeometry(width / 2, width / 2, tipSideLength, 32);\n        } else {\n          geometryTwo = new this.THREE.BoxGeometry(depth, tipSideLength, width);\n        }\n\n        geometryTwo.translate(0, -axis.length + tipSideLength / 2 + tipData.height, 0);\n        let cubeTwo;\n\n        if (propertiesData.fastener.tipSide) {\n          let lineProps = propertiesData.fastener.tipSide.line;\n          let materialTwo = this.GraphicsThree3D.getMaterialFromColor(propertiesData.fastener.tipSide.volume.color);\n          cubeTwo = new this.THREE.Mesh(geometryTwo, materialTwo);\n          cubeTwo.position.x = offsetFromCenter - shank.size / 2 * positiveOrNegative;\n          returnMeshes.push(cubeTwo);\n\n          if (geometryTwo.type == \"BoxGeometry\") {\n            let partOne = [];\n            let partTwo = [];\n            let geoVertices = [...geometryTwo.vertices].map(vertex => vertex.clone().add(new this.THREE.Vector3(cubeTwo.position.x, 0, 0)));\n            let firstPart = geoVertices[0].y;\n            geoVertices.forEach(vertex => {\n              if (vertex.y == firstPart) partOne.push(vertex);else partTwo.push(vertex);\n            });\n\n            if (!propertiesData.fastener.headSide) {\n              let wireframeOne = this.drawLineFromPoints(partOne, lineProps, true);\n              axisWireframes.push([wireframeOne]);\n            }\n\n            if (!tipData) {\n              let wireframeTwo = this.drawLineFromPoints(partTwo, lineProps, true);\n              axisWireframes.push([wireframeTwo]);\n            } else if (tipData.type == 3 || tipData.type == 4) {\n              for (let i = 0; i <= 2; i += 2) {\n                let wireframeTwo = this.drawLineFromPoints(partTwo.slice(i, i + 2), lineProps, true);\n                axisWireframes.push([wireframeTwo]);\n              }\n            }\n\n            let edgesLineArr = [];\n\n            for (let i = 0; i < partOne.length; i++) {\n              let newLine = this.drawLineFromPoints([partOne[i], partTwo[i]], lineProps);\n              edgesLineArr.push(newLine);\n            }\n\n            axisWireframes.push(edgesLineArr);\n          } else {\n            let partOne = [];\n            let partTwo = [];\n            let geoVertices = geometryTwo.vertices;\n            let firstPart = geoVertices[0].y;\n            geoVertices.forEach(vertex => {\n              if (vertex.y == firstPart) partOne.push(vertex);else partTwo.push(vertex);\n            });\n            partOne.splice(partOne.length - 1, 1);\n            partTwo.splice(partTwo.length - 1, 1);\n\n            if (!propertiesData.fastener.headSide) {\n              let wireframeOne = this.drawLineFromPoints(partOne, lineProps, true);\n              wireframeOne.position.x += offsetFromCenter - positiveOrNegative * width / 2;\n              axisWireframes.push([wireframeOne]);\n            }\n\n            if (!tipData) {\n              let wireframeTwo = this.drawLineFromPoints(partTwo, lineProps, true);\n              wireframeTwo.position.x += offsetFromCenter - positiveOrNegative * width / 2;\n              axisWireframes.push([wireframeTwo]);\n            }\n          }\n        }\n      }\n\n      if (shank.type == 1) {\n        geometry = new this.THREE.CylinderGeometry(width / 2, width / 2, height, 32);\n      } else if (shank.type == 2) {\n        geometry = new this.THREE.BoxGeometry(depth, height, width);\n        let cubeWireframe = [];\n        let pointsOne = [new this.THREE.Vector3(-width / 2, 0, -depth / 2), new this.THREE.Vector3(-width / 2, 0, depth / 2), new this.THREE.Vector3(width / 2, 0, depth / 2), new this.THREE.Vector3(width / 2, 0, -depth / 2)];\n        let pointsTwo = [new this.THREE.Vector3(-width / 2, -height, -depth / 2), new this.THREE.Vector3(-width / 2, -height, depth / 2), new this.THREE.Vector3(width / 2, -height, depth / 2), new this.THREE.Vector3(width / 2, -height, -depth / 2)];\n\n        if (isLeft) {\n          pointsOne.map((point, index) => {\n            if (index > 1) point.sub(new this.THREE.Vector3(0, width, 0));\n          });\n        } else {\n          pointsOne.map((point, index) => {\n            if (index < 2) point.sub(new this.THREE.Vector3(0, width, 0));\n          });\n        }\n\n        for (let i = 0; i < pointsOne.length; i++) {\n          pointsOne[i].add(new this.THREE.Vector3(offsetFromCenter - positiveOrNegative * width / 2, 0, 0));\n          pointsTwo[i].add(new this.THREE.Vector3(offsetFromCenter - positiveOrNegative * width / 2, 0, 0));\n          let newLine = this.drawLineFromPoints([pointsOne[i], pointsTwo[i]], lineProps);\n          cubeWireframe.push(newLine);\n        }\n\n        axisWireframes.push(cubeWireframe);\n\n        if (tipData && (tipData.type == 3 || tipData.type == 4) && !propertiesData.fastener.tipSide) {\n          for (let i = 0; i <= 2; i += 2) {\n            let sideWireframe = this.drawLineFromPoints(pointsTwo.slice(i, i + 2), lineProps, true);\n            axisWireframes.push([sideWireframe]);\n          }\n        }\n      }\n\n      geometry.translate(0, -height / 2, 0); ///\n\n      let cube;\n      let eraserBoxSize = Math.sqrt(2 * Math.pow(depth, 2));\n      let eraserBox = new this.THREE.Mesh(new this.THREE.BoxGeometry(eraserBoxSize, eraserBoxSize, eraserBoxSize));\n      eraserBox.rotation.z = Math.PI / 4;\n      eraserBox.position.set(isLeft ? depth / 2 : -depth / 2, 0, 0);\n      eraserBox.updateMatrix();\n      let geomesh = new this.THREE.Mesh(geometry);\n      let eraserCSG = this.GraphicsThree3D.CSG.fromMesh(eraserBox);\n      let geoCSG = this.GraphicsThree3D.CSG.fromMesh(geomesh);\n      let cubeGeoCSG = geoCSG.subtract(eraserCSG);\n      cube = this.GraphicsThree3D.CSG.toMesh(cubeGeoCSG, new this.THREE.Matrix4());\n      cube.material = material; ///\n\n      cube.position.x = offsetFromCenter - shank.size / 2 * positiveOrNegative;\n      returnMeshes.push(cube);\n      if (returnMeshes.length == 1) returnMeshes.push(null);\n      return [...returnMeshes, axisWireframes];\n    }\n\n    drawClampTip(shank, propertiesData, tip, isLeft, tipGeo) {\n      let tipSideProps = propertiesData.fastener.tipSide;\n      let headSideLineProps = propertiesData.fastener.headSide.line;\n      const colorAxis = tipSideProps && shank.tipSideLength ? tipSideProps.volume.color : propertiesData.fastener.headSide.volume.color;\n      let addTopWireframe = true;\n\n      if (shank.type == 1 && (tip.type == 1 || tip.type == 2)) {\n        addTopWireframe = false;\n      } else if (shank.type == 2 && (tip.type == 3 || tip.type == 4 || tip.type == 5 || tip.type == 6)) {\n        addTopWireframe = false;\n      }\n\n      let tipWireframes = this.makeTipWireframe(tip, tipGeo, tipSideProps && shank.tipSideLength ? tipSideProps.line : headSideLineProps, addTopWireframe);\n      let material = this.GraphicsThree3D.getMaterialFromColor(colorAxis);\n      var cylinder = new this.THREE.Mesh(tipGeo, material);\n      var offsetFromCenter = isLeft ? -(shank.offsetLength / 2) : shank.offsetLength / 2;\n      var positiveOrNegative = Math.sign(offsetFromCenter);\n      cylinder.position.x = offsetFromCenter - shank.size / 2 * positiveOrNegative;\n      tipWireframes.forEach(wireframe => wireframe.forEach(line => line.position.add(new this.THREE.Vector3(cylinder.position.x, 0, 0))));\n      return [cylinder, tipWireframes];\n    }\n\n    getLineMaterial(lineProps) {\n      let lineColor = lineProps.color;\n      let materialOptions = {\n        color: \"rgb(\" + lineColor.red + \", \" + lineColor.green + \", \" + lineColor.blue + \")\",\n        transparent: true,\n        opacity: lineColor.alpha / 255\n      };\n      let lineMaterial = new this.THREE.LineBasicMaterial(materialOptions);\n      return lineMaterial;\n    }\n\n    getEllipsePointsXZ(radiusX, radiusZ, rotationZ, position) {\n      let geo = new this.THREE.CircleGeometry(radiusZ, 32);\n      geo.applyMatrix4(new this.THREE.Matrix4().makeScale(1, radiusX / radiusZ, 1));\n      geo.rotateY(Math.PI / 2);\n      geo.rotateZ(rotationZ);\n      geo.translate(position.x, position.y, position.z);\n      let vertices = geo.vertices;\n      vertices.splice(0, 1);\n      return vertices;\n    }\n\n  }\n\n  _exports.FastenerLoader = FastenerLoader;\n\n  class Spiral {\n    constructor(spiralRadius, spiralHeight, initDist, spiralDebth, spiralRowWidth, material, parent, color = 0xffaa00) {\n      this.color = color;\n      this.initDist = initDist;\n      this.spiralHeight = spiralHeight;\n      this.spiralDebth = spiralDebth;\n      this.spiralRadius = spiralRadius;\n      this.spiralRowWidth = spiralRowWidth;\n      this.currentHeight = -spiralHeight / 2;\n      this.x = 0;\n      this.y = 0;\n      this.angle = 0;\n      this.xPlus = 0;\n      this.zPlus = 0;\n      this.material = material;\n      this.parent = parent; //this.geometry = geometry;\n    }\n\n    currentPosition(dist) {\n      return this.currentHeight += dist;\n    }\n\n    currentAngle() {\n      this.angle -= 360 / 32;\n      this.x = Math.cos(Math.PI / 180 * this.angle);\n      this.z = Math.sin(Math.PI / 180 * this.angle);\n    }\n\n    getCylGeo() {\n      if (this.spiralHeight > 0 && this.spiralRadius == 0) this.spiralRadius += 0.0001;\n      const cylinder = new this.parent.THREE.CylinderGeometry(this.spiralRadius, this.spiralRadius, this.spiralHeight, 32);\n      cylinder.translate(0, -this.spiralHeight / 2, 0);\n      return cylinder;\n    }\n\n    getSpiralGeo() {\n      let wireframePoints = [[], [], []];\n      const dist = this.initDist / 32;\n      const c = this.currentPosition(dist);\n      this.currentAngle();\n      var geometry = new this.parent.THREE.Geometry();\n      let pointOne = new this.parent.THREE.Vector3(this.spiralRadius * this.x, c, this.spiralRadius * this.z);\n      let pointTwo = new this.parent.THREE.Vector3((this.spiralDebth + this.spiralRadius) * this.x, c - this.spiralRowWidth / 2, (this.spiralDebth + this.spiralRadius) * this.z);\n      let pointThree = new this.parent.THREE.Vector3(this.spiralRadius * this.x, c - this.spiralRowWidth, this.spiralRadius * this.z);\n      geometry.vertices.push(pointOne);\n      geometry.vertices.push(pointTwo);\n      geometry.vertices.push(pointThree);\n      wireframePoints[0].push(pointOne);\n      wireframePoints[1].push(pointTwo);\n      wireframePoints[2].push(pointThree);\n      var face0 = new this.parent.THREE.Face3(0, 1, 2);\n      geometry.faces.push(face0);\n      var l = 0;\n\n      for (let i = 0; i < 32 * (this.spiralHeight - this.spiralRowWidth) / this.initDist; i++) {\n        const c1 = this.currentPosition(dist);\n        this.currentAngle();\n        pointOne = new this.parent.THREE.Vector3(this.spiralRadius * this.x, c1, this.spiralRadius * this.z);\n        pointTwo = new this.parent.THREE.Vector3((this.spiralDebth + this.spiralRadius) * this.x, c1 - this.spiralRowWidth / 2, (this.spiralDebth + this.spiralRadius) * this.z);\n        pointThree = new this.parent.THREE.Vector3(this.spiralRadius * this.x, c1 - this.spiralRowWidth, this.spiralRadius * this.z);\n        geometry.vertices.push(pointOne);\n        geometry.vertices.push(pointTwo);\n        geometry.vertices.push(pointThree);\n        wireframePoints[0].push(pointOne);\n        wireframePoints[1].push(pointTwo);\n        wireframePoints[2].push(pointThree);\n        var face1 = new this.parent.THREE.Face3(l + 1, l + 3, l + 4);\n        var face2 = new this.parent.THREE.Face3(l + 1, l, l + 3);\n        var face3 = new this.parent.THREE.Face3(l, l + 2, l + 5);\n        var face4 = new this.parent.THREE.Face3(l, l + 3, l + 5);\n        var face5 = new this.parent.THREE.Face3(l + 1, l + 3, l + 2);\n        var face6 = new this.parent.THREE.Face3(l + 1, l + 4, l + 3);\n        var face7 = new this.parent.THREE.Face3(l + 1, l + 5, l + 2);\n        var face8 = new this.parent.THREE.Face3(l + 1, l + 4, l + 5);\n        var face9 = new this.parent.THREE.Face3(l, l + 1, l + 2); //add the face to the geometry's faces array\n\n        geometry.faces.push(face1);\n        geometry.faces.push(face2);\n        geometry.faces.push(face3);\n        geometry.faces.push(face4);\n        geometry.faces.push(face5);\n        geometry.faces.push(face6);\n        geometry.faces.push(face7);\n        geometry.faces.push(face8);\n        geometry.faces.push(face9); ///\n        // let testFaceOne = new this.parent.THREE.Face3(l, l + 1, l + 3);\n        // let testFaceTwo = new this.parent.THREE.Face3(l + 1, l + 4, l + 3);\n        // let testFaceThree = new this.parent.THREE.Face3(l + 1, l + 2, l + 4);\n        // let testFaceFour = new this.parent.THREE.Face3(l + 2, l + 5, l + 4);\n        // geometry.faces.push(testFaceOne);\n        // geometry.faces.push(testFaceTwo);\n        // geometry.faces.push(testFaceThree);\n        // geometry.faces.push(testFaceFour);\n\n        l += 3;\n      }\n\n      geometry.computeFaceNormals();\n      geometry.computeVertexNormals();\n      geometry.translate(0, -this.spiralHeight / 2 + this.spiralRowWidth - this.initDist / 32, 0);\n      wireframePoints.forEach(points => {\n        points.map(point => point = point.clone().setComponent(1, -this.spiralHeight / 2 + this.spiralRowWidth - this.initDist / 32));\n      });\n      return [geometry, wireframePoints];\n    }\n\n  }\n});","define(\"m08-2020/lib/OutlinesGeometry\", [\"exports\", \"three\"], function (_exports, THREE) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.OutlinesGeometry = OutlinesGeometry;\n\n  function OutlinesGeometry(geometry, thresholdAngle) {\n    /**\n     * https://github.com/mrdoob/three.js/issues/10517\n     */\n    // THREE.BufferGeometry.call( this );\n    THREE.Geometry.call(this);\n    thresholdAngle = thresholdAngle !== undefined ? thresholdAngle : 1;\n    var thresholdDot = Math.cos(Math.PI / 180 * thresholdAngle);\n    var edge = [0, 0],\n        hash = {},\n        i,\n        j,\n        l,\n        face,\n        key;\n\n    function sortFunction(a, b) {\n      return a - b;\n    }\n\n    var keys = ['a', 'b', 'c'];\n    var geometry2;\n\n    if (geometry.isBufferGeometry) {\n      geometry2 = new THREE.Geometry();\n      geometry2.fromBufferGeometry(geometry);\n    } else {\n      geometry2 = geometry.clone();\n    }\n\n    geometry2.mergeVertices();\n    geometry2.computeFaceNormals();\n    var vertices = geometry2.vertices;\n    var faces = geometry2.faces;\n\n    for (i = 0; i < faces.length; i++) {\n      face = faces[i];\n\n      for (j = 0; j < 3; j++) {\n        edge[0] = face[keys[j]];\n        edge[1] = face[keys[(j + 1) % 3]];\n        var line = new THREE.Line3(vertices[edge[0]], vertices[edge[1]]); // for each vertex checks if it lies in the edge\n\n        for (var e = vertices.length - 1; e >= 0; e--) {\n          if (e === edge[0] || e === edge[1]) continue;\n          var v = vertices[e];\n          var closestPoint = line.closestPointToPoint(v, true, new THREE.Vector3());\n\n          if (new THREE.Line3(closestPoint, v).distance() < 1e-5) {\n            //1e-5\n            // mark the current face as splitted so that his cords won't be considered\n            face.splitted = true; // Add two new faces, created splitting the face in two\n\n            faces.push(new THREE.Face3(e, face[keys[(j + 2) % 3]], face[keys[j % 3]], face.normal, face.color, face.materialIndex));\n            faces.push(new THREE.Face3(e, face[keys[(j + 2) % 3]], face[keys[(j + 1) % 3]], face.normal, face.color, face.materialIndex));\n            break;\n          }\n        }\n\n        if (face.splitted) break;\n      }\n    }\n\n    for (i = faces.length - 1; i >= 0; i--) {\n      face = faces[i];\n      if (face.splitted) continue;\n\n      for (j = 0; j < 3; j++) {\n        edge[0] = face[keys[j]];\n        edge[1] = face[keys[(j + 1) % 3]];\n        edge.sort(sortFunction);\n        key = edge.toString();\n\n        if (hash[key] === undefined) {\n          hash[key] = {\n            vert1: edge[0],\n            vert2: edge[1],\n            face1: i,\n            face2: undefined\n          };\n        } else {\n          hash[key].face2 = i;\n        }\n      }\n    }\n\n    var coords = [];\n\n    for (key in hash) {\n      var h = hash[key]; // An edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.\n\n      if (h.face2 !== undefined && faces[h.face1].normal.dot(faces[h.face2].normal) <= thresholdDot) {\n        var vertex = vertices[h.vert1];\n        coords.push(vertex.x);\n        coords.push(vertex.y);\n        coords.push(vertex.z);\n        vertex = vertices[h.vert2];\n        coords.push(vertex.x);\n        coords.push(vertex.y);\n        coords.push(vertex.z);\n      }\n    } // this.setAttribute( 'position', new THREE.Float32BufferAttribute( coords, 3 ) );\n    ///\n\n\n    this.vertices = vertices;\n    this.faces = faces;\n  }\n\n  OutlinesGeometry.prototype = Object.create(THREE.BufferGeometry.prototype);\n  OutlinesGeometry.prototype.constructor = OutlinesGeometry;\n});","define(\"m08-2020/lib/SectionalPlane\", [\"exports\", \"three\", \"m08-2020/lib/Utils\"], function (_exports, THREE, _Utils) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.SectionalPlane = void 0;\n  let utils = new _Utils.Utils(THREE);\n\n  class SectionalPlane {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.clipObjects = [];\n      this.renderOrder = 1;\n    }\n\n    applySectionalPlanes(sectionalPlanes, properties) {\n      let intersectionLineProps = properties.intersectionLine;\n      let intersectionAreaProps = properties.intersectionArea; // TODO: Implement sectionalPlane properties for lines and hatching\n\n      sectionalPlanes.forEach(sectionalPlane => this.applySectionalPlane(sectionalPlane, intersectionAreaProps ? intersectionAreaProps : intersectionLineProps));\n    }\n\n    applySectionalPlane(sectionalPlaneData, intersectionAreaProps) {\n      let positionVector = utils.initVector3(sectionalPlaneData.positionVector);\n      let normalVector = utils.initVector3(sectionalPlaneData.normalVector).negate();\n      let planeDistance = positionVector.clone().multiply(normalVector).length();\n      let distanceSign = positionVector.normalize().dot(normalVector) > 0 ? -1 : 1;\n      planeDistance *= distanceSign;\n      let clippingPlane = new THREE.Plane(normalVector, planeDistance);\n      this.clipObjects.forEach(child => {\n        if (child.type == \"Mesh\" || child.type == \"Line\" || child.type == \"LineSegments\") {\n          this.clipMesh(clippingPlane, child, intersectionAreaProps);\n        }\n      });\n    }\n\n    clipMesh(clippingPlane, mesh, intersectionAreaProps) {\n      if (intersectionAreaProps) {\n        let [frontFaceStencilMat, backFaceStencilMat, planeStencilMat] = this.getClippingMaterials(intersectionAreaProps);\n        frontFaceStencilMat.clippingPlanes = [clippingPlane];\n        backFaceStencilMat.clippingPlanes = [clippingPlane];\n        let meshGeo = mesh.geometry.clone();\n        let frontMesh = new THREE.Mesh(meshGeo, frontFaceStencilMat);\n        frontMesh.applyMatrix4(mesh.matrix);\n        this.GraphicsThree3D.scene.add(frontMesh);\n        let backMesh = new THREE.Mesh(meshGeo, backFaceStencilMat);\n        backMesh.applyMatrix4(mesh.matrix);\n        this.GraphicsThree3D.scene.add(backMesh); ///\n\n        frontMesh.renderOrder = this.renderOrder;\n        frontMesh.renderOrder = this.renderOrder;\n        this.renderOrder++; ///\n\n        let planeNormal = clippingPlane.normal.clone();\n        let forwardVector = new THREE.Vector3(0, 0, -1);\n        let planeGeom = new THREE.PlaneBufferGeometry();\n        let planeMesh = new THREE.Mesh(planeGeom, planeStencilMat);\n        planeMesh.scale.setScalar(1000);\n        clippingPlane.coplanarPoint(planeMesh.position);\n        planeMesh.quaternion.setFromUnitVectors(forwardVector, planeNormal);\n        planeMesh.renderOrder = 1;\n        planeMesh.position.copy(mesh.position);\n        frontMesh.position.copy(mesh.position);\n        backMesh.position.copy(mesh.position);\n\n        planeMesh.onBeforeRender = function (renderer) {\n          renderer.clearDepth();\n        }; ///\n\n\n        planeMesh.onAfterRender = function (renderer) {\n          renderer.clearStencil();\n        };\n\n        planeMesh.renderOrder = this.renderOrder + 1.1; ///\n\n        this.GraphicsThree3D.scene.add(planeMesh);\n      } ///\n\n\n      if (mesh.children) mesh.children.forEach(child => this.clipMaterial(child.material, clippingPlane));\n      this.clipMaterial(mesh.material, clippingPlane);\n    }\n\n    clipMaterial(material, plane) {\n      if (material.length) material.forEach(mat => this.addClippingPlane(mat, plane));else this.addClippingPlane(material, plane);\n    }\n\n    addClippingPlane(material, plane) {\n      if (material.clippingPlanes) material.clippingPlanes.push(plane);else material.clippingPlanes = [plane];\n    }\n\n    getClippingMaterials(materialProps) {\n      let frontFaceStencilMat, backFaceStencilMat, planeStencilMat; //https://discourse.threejs.org/t/capping-clipped-planes-using-stencil-on-a-buffergeometry/18407/18\n      // PASS 1\n      // everywhere that the back faces are visible (clipped region) the stencil\n      // buffer is incremented by 1.\n\n      backFaceStencilMat = new THREE.MeshBasicMaterial();\n      backFaceStencilMat.depthWrite = false;\n      backFaceStencilMat.depthTest = false;\n      backFaceStencilMat.colorWrite = false;\n      backFaceStencilMat.stencilWrite = true;\n      backFaceStencilMat.stencilFunc = THREE.AlwaysStencilFunc;\n      backFaceStencilMat.side = THREE.BackSide;\n      backFaceStencilMat.stencilFail = THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZFail = THREE.IncrementWrapStencilOp;\n      backFaceStencilMat.stencilZPass = THREE.IncrementWrapStencilOp; // PASS 2\n      // everywhere that the front faces are visible the stencil\n      // buffer is decremented back to 0.\n\n      frontFaceStencilMat = new THREE.MeshBasicMaterial();\n      frontFaceStencilMat.depthWrite = false;\n      frontFaceStencilMat.depthTest = false;\n      frontFaceStencilMat.colorWrite = false;\n      frontFaceStencilMat.stencilWrite = true;\n      frontFaceStencilMat.stencilFunc = THREE.AlwaysStencilFunc;\n      frontFaceStencilMat.side = THREE.FrontSide;\n      frontFaceStencilMat.stencilFail = THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZFail = THREE.DecrementWrapStencilOp;\n      frontFaceStencilMat.stencilZPass = THREE.DecrementWrapStencilOp; // PASS 3\n      // draw the plane everywhere that the stencil buffer != 0, which will\n      // only be in the clipped region where back faces are visible.\n\n      planeStencilMat = this.getPlaneStencilMaterial(materialProps);\n      planeStencilMat.stencilWrite = true;\n      planeStencilMat.stencilRef = 0;\n      planeStencilMat.stencilFunc = THREE.NotEqualStencilFunc;\n      planeStencilMat.stencilFail = THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZFail = THREE.ReplaceStencilOp;\n      planeStencilMat.stencilZPass = THREE.ReplaceStencilOp;\n      return [frontFaceStencilMat, backFaceStencilMat, planeStencilMat];\n    }\n\n    getPlaneStencilMaterial(areaProps) {\n      const SIZE = 20;\n      let planeStencilMat;\n      let colorProps = areaProps.color;\n\n      if (areaProps.hatching.type === 2) {\n        let orientationVector = utils.normalizeVector(areaProps.hatching.orientationVector);\n        let hatchSpacing = areaProps.hatching.factor;\n        let hatchColor = areaProps.hatching.color;\n        let hatchThickness = areaProps.hatching.thickness;\n        planeStencilMat = this.GraphicsThree3D.makeCanvasMaterial(colorProps, hatchColor, orientationVector, hatchSpacing, hatchThickness);\n        planeStencilMat.map.wrapS = planeStencilMat.map.wrapT = THREE.RepeatWrapping;\n        planeStencilMat.map.repeat.set(SIZE, SIZE);\n        planeStencilMat.map.offset.set(0.5, 0.5);\n      } else if (areaProps.hatching.type === 1) {\n        planeStencilMat = this.GraphicsThree3D.getMaterialFromColor(colorProps);\n      } // planeStencilMat.side = THREE.FrontSide;\n\n\n      return planeStencilMat;\n    }\n\n    resetClipObjects() {\n      this.clipObjects = [];\n    }\n\n  }\n\n  _exports.SectionalPlane = SectionalPlane;\n});","define(\"m08-2020/lib/ThreeCSG\", [\"exports\"], function (_exports) {\n  'use strict';\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.ThreeBSP = void 0;\n  var THREE;\n\n  const ThreeBSP = function () {\n    var ThreeBSP,\n        EPSILON = 1e-5,\n        COPLANAR = 0,\n        FRONT = 1,\n        BACK = 2,\n        SPANNING = 3;\n\n    ThreeBSP = function (geometry, threeRef) {\n      // Convert THREE.Geometry to ThreeBSP\n      var i,\n          _length_i,\n          face,\n          vertex,\n          faceVertexUvs,\n          polygon,\n          polygons = [],\n          tree;\n\n      if (threeRef) {\n        THREE = threeRef;\n      }\n\n      if (geometry instanceof THREE.Geometry) {\n        this.matrix = new THREE.Matrix4();\n      } else if (geometry instanceof THREE.Mesh) {\n        // #todo: add hierarchy support\n        geometry.updateMatrix();\n        this.matrix = geometry.matrixWorld.clone(); // Lee was here -- changed matrix to matrixWorld\n\n        geometry = geometry.geometry;\n      } else if (geometry instanceof ThreeBSP.Node) {\n        this.tree = geometry;\n        this.matrix = new THREE.Matrix4();\n        return this;\n      } else {\n        throw 'ThreeBSP: Given geometry is unsupported';\n      }\n\n      for (i = 0, _length_i = geometry.faces.length; i < _length_i; i++) {\n        face = geometry.faces[i];\n        faceVertexUvs = geometry.faceVertexUvs[0][i];\n        polygon = new ThreeBSP.Polygon();\n\n        if (face instanceof THREE.Face3) {\n          vertex = geometry.vertices[face.a];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[0].u, faceVertexUvs[0].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.b];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[1], new THREE.Vector2(faceVertexUvs[1].u, faceVertexUvs[1].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.c];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[2], new THREE.Vector2(faceVertexUvs[2].u, faceVertexUvs[2].v));\n          polygon.vertices.push(vertex);\n        } else if (typeof THREE.Face4) {\n          vertex = geometry.vertices[face.a];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[0].u, faceVertexUvs[0].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.b];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[1], new THREE.Vector2(faceVertexUvs[1].u, faceVertexUvs[1].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.c];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[2], new THREE.Vector2(faceVertexUvs[2].u, faceVertexUvs[2].v));\n          polygon.vertices.push(vertex);\n          vertex = geometry.vertices[face.d];\n          vertex.applyMatrix4(this.matrix);\n          vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[3], new THREE.Vector2(faceVertexUvs[3].u, faceVertexUvs[3].v));\n          polygon.vertices.push(vertex);\n        } else {\n          throw 'Invalid face type at index ' + i;\n        }\n\n        polygon.calculateProperties();\n        polygons.push(polygon);\n      }\n\n      ;\n      this.tree = new ThreeBSP.Node(polygons);\n    };\n\n    ThreeBSP.prototype.subtract = function (other_tree) {\n      var a = this.tree.clone(),\n          b = other_tree.tree.clone();\n      a.invert();\n      a.clipTo(b);\n      b.clipTo(a);\n      b.invert();\n      b.clipTo(a);\n      b.invert();\n      a.build(b.allPolygons());\n      a.invert();\n      a = new ThreeBSP(a);\n      a.matrix = this.matrix;\n      return a;\n    };\n\n    ThreeBSP.prototype.union = function (other_tree) {\n      var a = this.tree.clone(),\n          b = other_tree.tree.clone();\n      a.clipTo(b);\n      b.clipTo(a);\n      b.invert();\n      b.clipTo(a);\n      b.invert();\n      a.build(b.allPolygons());\n      a = new ThreeBSP(a);\n      a.matrix = this.matrix;\n      return a;\n    };\n\n    ThreeBSP.prototype.intersect = function (other_tree) {\n      var a = this.tree.clone(),\n          b = other_tree.tree.clone();\n      a.invert();\n      b.clipTo(a);\n      b.invert();\n      a.clipTo(b);\n      b.clipTo(a);\n      a.build(b.allPolygons());\n      a.invert();\n      a = new ThreeBSP(a);\n      a.matrix = this.matrix;\n      return a;\n    };\n\n    ThreeBSP.prototype.toGeometry = function () {\n      var i,\n          j,\n          matrix = new THREE.Matrix4().getInverse(this.matrix),\n          geometry = new THREE.Geometry(),\n          polygons = this.tree.allPolygons(),\n          polygon_count = polygons.length,\n          polygon,\n          polygon_vertice_count,\n          vertice_dict = {},\n          vertex_idx_a,\n          vertex_idx_b,\n          vertex_idx_c,\n          vertex,\n          face,\n          verticeNormals,\n          verticeUvs;\n\n      for (i = 0; i < polygon_count; i++) {\n        polygon = polygons[i];\n        polygon_vertice_count = polygon.vertices.length;\n\n        for (j = 2; j < polygon_vertice_count; j++) {\n          verticeNormals = [];\n          verticeUvs = [];\n          vertex = polygon.vertices[0];\n          verticeNormals.push(vertex.normal);\n          verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));\n          vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);\n          vertex.applyMatrix4(matrix);\n\n          if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined') {\n            vertex_idx_a = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];\n          } else {\n            geometry.vertices.push(vertex);\n            vertex_idx_a = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;\n          }\n\n          vertex = polygon.vertices[j - 1];\n          verticeNormals.push(vertex.normal);\n          verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));\n          vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);\n          vertex.applyMatrix4(matrix);\n\n          if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined') {\n            vertex_idx_b = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];\n          } else {\n            geometry.vertices.push(vertex);\n            vertex_idx_b = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;\n          }\n\n          vertex = polygon.vertices[j];\n          verticeNormals.push(vertex.normal);\n          verticeUvs.push(new THREE.Vector2(vertex.uv.x, vertex.uv.y));\n          vertex = new THREE.Vector3(vertex.x, vertex.y, vertex.z);\n          vertex.applyMatrix4(matrix);\n\n          if (typeof vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] !== 'undefined') {\n            vertex_idx_c = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];\n          } else {\n            geometry.vertices.push(vertex);\n            vertex_idx_c = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = geometry.vertices.length - 1;\n          }\n\n          face = new THREE.Face3(vertex_idx_a, vertex_idx_b, vertex_idx_c, new THREE.Vector3(polygon.normal.x, polygon.normal.y, polygon.normal.z));\n          face.vertexNormals.push(verticeNormals[0], verticeNormals[1], verticeNormals[2]);\n          geometry.faces.push(face);\n          geometry.faceVertexUvs[0].push(verticeUvs);\n        }\n      }\n\n      return geometry;\n    };\n\n    ThreeBSP.prototype.toMesh = function (material) {\n      var geometry = this.toGeometry(),\n          mesh = new THREE.Mesh(geometry, material);\n      mesh.position.getPositionFromMatrix(this.matrix); //mesh.rotation.setEulerFromRotationMatrix( this.matrix );//not working and commented\n\n      mesh.position.setFromMatrixPosition(this.matrix); //from stackoverflow (https://stackoverflow.com/questions/17711914/seteulerfromrotationmatrix-does-not-exist-in-three-js)\n\n      return mesh;\n    };\n\n    ThreeBSP.Polygon = function (vertices, normal, w) {\n      if (!(vertices instanceof Array)) {\n        vertices = [];\n      }\n\n      this.vertices = vertices;\n\n      if (vertices.length > 0) {\n        this.calculateProperties();\n      } else {\n        this.normal = this.w = undefined;\n      }\n    };\n\n    ThreeBSP.Polygon.prototype.calculateProperties = function () {\n      var a = this.vertices[0],\n          b = this.vertices[1],\n          c = this.vertices[2];\n      this.normal = b.clone().subtract(a).cross(c.clone().subtract(a)).normalize();\n      this.w = this.normal.clone().dot(a);\n      return this;\n    };\n\n    ThreeBSP.Polygon.prototype.clone = function () {\n      var i,\n          vertice_count,\n          polygon = new ThreeBSP.Polygon();\n\n      for (i = 0, vertice_count = this.vertices.length; i < vertice_count; i++) {\n        polygon.vertices.push(this.vertices[i].clone());\n      }\n\n      ;\n      polygon.calculateProperties();\n      return polygon;\n    };\n\n    ThreeBSP.Polygon.prototype.flip = function () {\n      var i,\n          vertices = [];\n      this.normal.multiplyScalar(-1);\n      this.w *= -1;\n\n      for (i = this.vertices.length - 1; i >= 0; i--) {\n        //this.vertices[i].normal.multiplyScalar( -1 );\n        vertices.push(this.vertices[i]);\n      }\n\n      ;\n      this.vertices = vertices;\n      return this;\n    };\n\n    ThreeBSP.Polygon.prototype.classifyVertex = function (vertex) {\n      var side_value = this.normal.dot(vertex) - this.w;\n\n      if (side_value < -EPSILON) {\n        return BACK;\n      } else if (side_value > EPSILON) {\n        return FRONT;\n      } else {\n        return COPLANAR;\n      }\n    };\n\n    ThreeBSP.Polygon.prototype.classifySide = function (polygon) {\n      var i,\n          vertex,\n          classification,\n          num_positive = 0,\n          num_negative = 0,\n          vertice_count = polygon.vertices.length;\n\n      for (i = 0; i < vertice_count; i++) {\n        vertex = polygon.vertices[i];\n        classification = this.classifyVertex(vertex);\n\n        if (classification === FRONT) {\n          num_positive++;\n        } else if (classification === BACK) {\n          num_negative++;\n        }\n      }\n\n      if (num_positive > 0 && num_negative === 0) {\n        return FRONT;\n      } else if (num_positive === 0 && num_negative > 0) {\n        return BACK;\n      } else if (num_positive === 0 && num_negative === 0) {\n        return COPLANAR;\n      } else {\n        return SPANNING;\n      }\n    };\n\n    ThreeBSP.Polygon.prototype.splitPolygon = function (polygon, coplanar_front, coplanar_back, front, back) {\n      var classification = this.classifySide(polygon);\n\n      if (classification === COPLANAR) {\n        (this.normal.dot(polygon.normal) > 0 ? coplanar_front : coplanar_back).push(polygon);\n      } else if (classification === FRONT) {\n        front.push(polygon);\n      } else if (classification === BACK) {\n        back.push(polygon);\n      } else {\n        var vertice_count,\n            i,\n            j,\n            ti,\n            tj,\n            vi,\n            vj,\n            t,\n            v,\n            f = [],\n            b = [];\n\n        for (i = 0, vertice_count = polygon.vertices.length; i < vertice_count; i++) {\n          j = (i + 1) % vertice_count;\n          vi = polygon.vertices[i];\n          vj = polygon.vertices[j];\n          ti = this.classifyVertex(vi);\n          tj = this.classifyVertex(vj);\n          if (ti != BACK) f.push(vi);\n          if (ti != FRONT) b.push(vi);\n\n          if ((ti | tj) === SPANNING) {\n            t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().subtract(vi));\n            v = vi.interpolate(vj, t);\n            f.push(v);\n            b.push(v);\n          }\n        }\n\n        if (f.length >= 3) front.push(new ThreeBSP.Polygon(f).calculateProperties());\n        if (b.length >= 3) back.push(new ThreeBSP.Polygon(b).calculateProperties());\n      }\n    };\n\n    ThreeBSP.Vertex = function (x, y, z, normal, uv) {\n      this.x = x;\n      this.y = y;\n      this.z = z;\n      this.normal = normal || new THREE.Vector3();\n      this.uv = uv || new THREE.Vector2();\n    };\n\n    ThreeBSP.Vertex.prototype.clone = function () {\n      return new ThreeBSP.Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone());\n    };\n\n    ThreeBSP.Vertex.prototype.add = function (vertex) {\n      this.x += vertex.x;\n      this.y += vertex.y;\n      this.z += vertex.z;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.subtract = function (vertex) {\n      this.x -= vertex.x;\n      this.y -= vertex.y;\n      this.z -= vertex.z;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.multiplyScalar = function (scalar) {\n      this.x *= scalar;\n      this.y *= scalar;\n      this.z *= scalar;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.cross = function (vertex) {\n      var x = this.x,\n          y = this.y,\n          z = this.z;\n      this.x = y * vertex.z - z * vertex.y;\n      this.y = z * vertex.x - x * vertex.z;\n      this.z = x * vertex.y - y * vertex.x;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.normalize = function () {\n      var length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\n      this.x /= length;\n      this.y /= length;\n      this.z /= length;\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.dot = function (vertex) {\n      return this.x * vertex.x + this.y * vertex.y + this.z * vertex.z;\n    };\n\n    ThreeBSP.Vertex.prototype.lerp = function (a, t) {\n      this.add(a.clone().subtract(this).multiplyScalar(t));\n      this.normal.add(a.normal.clone().sub(this.normal).multiplyScalar(t));\n      this.uv.add(a.uv.clone().sub(this.uv).multiplyScalar(t));\n      return this;\n    };\n\n    ThreeBSP.Vertex.prototype.interpolate = function (other, t) {\n      return this.clone().lerp(other, t);\n    };\n\n    ThreeBSP.Node = function (polygons) {\n      var i,\n          polygon_count,\n          front = [],\n          back = [];\n      this.polygons = [];\n      this.front = this.back = undefined;\n      if (!(polygons instanceof Array) || polygons.length === 0) return;\n      this.divider = polygons[0].clone();\n\n      for (i = 0, polygon_count = polygons.length; i < polygon_count; i++) {\n        this.divider.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);\n      }\n\n      if (front.length > 0) {\n        this.front = new ThreeBSP.Node(front);\n      }\n\n      if (back.length > 0) {\n        this.back = new ThreeBSP.Node(back);\n      }\n    };\n\n    ThreeBSP.Node.prototype.build = function (polygons) {\n      var i,\n          polygon_count,\n          front = [],\n          back = [];\n\n      if (!this.divider) {\n        this.divider = polygons[0].clone();\n      }\n\n      for (i = 0, polygon_count = polygons.length; i < polygon_count; i++) {\n        this.divider.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);\n      }\n\n      if (front.length > 0) {\n        if (!this.front) this.front = new ThreeBSP.Node();\n        this.front.build(front);\n      }\n\n      if (back.length > 0) {\n        if (!this.back) this.back = new ThreeBSP.Node();\n        this.back.build(back);\n      }\n    };\n\n    ThreeBSP.Node.prototype.allPolygons = function () {\n      var polygons = this.polygons.slice();\n      if (this.front) polygons = polygons.concat(this.front.allPolygons());\n      if (this.back) polygons = polygons.concat(this.back.allPolygons());\n      return polygons;\n    };\n\n    ThreeBSP.Node.prototype.clone = function () {\n      var node = new ThreeBSP.Node();\n      node.divider = this.divider.clone();\n      node.polygons = this.polygons.map(function (polygon) {\n        return polygon.clone();\n      });\n      node.front = this.front && this.front.clone();\n      node.back = this.back && this.back.clone();\n      return node;\n    };\n\n    ThreeBSP.Node.prototype.invert = function () {\n      var i, polygon_count, temp;\n\n      for (i = 0, polygon_count = this.polygons.length; i < polygon_count; i++) {\n        this.polygons[i].flip();\n      }\n\n      this.divider.flip();\n      if (this.front) this.front.invert();\n      if (this.back) this.back.invert();\n      temp = this.front;\n      this.front = this.back;\n      this.back = temp;\n      return this;\n    };\n\n    ThreeBSP.Node.prototype.clipPolygons = function (polygons) {\n      var i, polygon_count, front, back;\n      if (!this.divider) return polygons.slice();\n      front = [], back = [];\n\n      for (i = 0, polygon_count = polygons.length; i < polygon_count; i++) {\n        this.divider.splitPolygon(polygons[i], front, back, front, back); //if (window.debug) console.debug( front.length, back.length );\n      }\n\n      if (this.front) front = this.front.clipPolygons(front);\n      if (this.back) back = this.back.clipPolygons(back);else back = [];\n      return front.concat(back);\n    };\n\n    ThreeBSP.Node.prototype.clipTo = function (node) {\n      this.polygons = node.clipPolygons(this.polygons);\n      if (this.front) this.front.clipTo(node);\n      if (this.back) this.back.clipTo(node);\n    };\n\n    return ThreeBSP;\n  }();\n\n  _exports.ThreeBSP = ThreeBSP;\n});","define(\"m08-2020/lib/ThreeExtensions/CustomEllipseCurve\", [\"exports\", \"three\"], function (_exports, THREE) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.CustomEllipseCurve = void 0;\n\n  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n  class CustomEllipseCurve extends THREE.EllipseCurve {\n    constructor(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation, rotationPitch) {\n      super(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation);\n\n      _defineProperty(this, \"getPoint\", function (t) {\n        // this is modified version of three js curve.getPoint to return vector3 instead of vector2;\n        const point = new THREE.Vector3();\n        const twoPi = Math.PI * 2;\n        let deltaAngle = this.aEndAngle - this.aStartAngle;\n        const samePoints = Math.abs(deltaAngle) < Number.EPSILON; // ensures that deltaAngle is 0 .. 2 PI\n\n        while (deltaAngle < 0) deltaAngle += twoPi;\n\n        while (deltaAngle > twoPi) deltaAngle -= twoPi;\n\n        if (deltaAngle < Number.EPSILON) {\n          if (samePoints) {\n            deltaAngle = 0;\n          } else {\n            deltaAngle = twoPi;\n          }\n        }\n\n        if (this.aClockwise === true && !samePoints) {\n          if (deltaAngle === twoPi) {\n            deltaAngle = -twoPi;\n          } else {\n            deltaAngle = deltaAngle - twoPi;\n          }\n        }\n\n        const angle = this.aStartAngle + t * deltaAngle;\n        let x = this.aX + this.xRadius * Math.cos(angle);\n        let y = this.aY + this.yRadius * Math.sin(angle);\n\n        if (this.aRotation !== 0) {\n          const cos = Math.cos(this.aRotation);\n          const sin = Math.sin(this.aRotation);\n          const tx = x - this.aX;\n          const ty = y - this.aY; // Rotate the point about the center of the ellipse.\n\n          x = tx * cos - ty * sin + this.aX;\n          y = tx * sin + ty * cos + this.aY;\n        }\n\n        return point.set(x, -t * this.rotationPitch, y);\n      });\n\n      _defineProperty(this, \"getTangent\", function (t) {\n        // this is modified version of three js getTangent to modify tangent vector;\n        const delta = 0.0001;\n        let t1 = t - delta;\n        let t2 = t + delta; // Capping in case of danger\n\n        if (t1 < 0) t1 = 0;\n        if (t2 > 1) t2 = 1;\n        const pt1 = this.getPoint(t1);\n        const pt2 = this.getPoint(t2);\n        const tangent = new THREE.Vector3();\n        tangent.copy(pt2).add(new THREE.Vector3(0, this.rotationPitch * delta, 0)).sub(pt1).normalize();\n        return tangent;\n      });\n\n      _defineProperty(this, \"computeFrenetFrames\", function (segments, closed) {\n        // this is modified version of three js computeFrenetFrames to modify normal vector;\n        // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf\n        const normal = new THREE.Vector3();\n        const tangents = [];\n        const normals = [];\n        const binormals = [];\n        const vec = new THREE.Vector3();\n        const mat = new THREE.Matrix4(); // compute the tangent vectors for each segment on the curve\n\n        for (let i = 0; i <= segments; i++) {\n          const u = i / segments;\n          tangents[i] = this.getTangentAt(u, new THREE.Vector3());\n          tangents[i].normalize();\n        } // select an initial normal vector perpendicular to the first tangent vector,\n        // and in the direction of the minimum tangent xyz component\n\n\n        normals[0] = new THREE.Vector3();\n        binormals[0] = new THREE.Vector3();\n        let min = Number.MAX_VALUE;\n        const tx = Math.abs(tangents[0].x);\n        const ty = Math.abs(tangents[0].y);\n        const tz = Math.abs(tangents[0].z);\n\n        if (tx <= min) {\n          min = tx;\n          normal.set(1, 0, 0);\n        }\n\n        if (ty <= min) {\n          min = ty;\n          normal.set(0, 1, 0);\n        }\n\n        if (tz <= min) {\n          normal.set(0, 0, 1);\n        }\n\n        vec.crossVectors(tangents[0], normal).normalize();\n        normals[0].crossVectors(tangents[0], vec);\n        binormals[0].crossVectors(tangents[0], normals[0]); // compute the slowly-varying normal and binormal vectors for each segment on the curve\n\n        for (let i = 1; i <= segments; i++) {\n          normals[i] = normals[i - 1].clone();\n          binormals[i] = binormals[i - 1].clone();\n          vec.crossVectors(tangents[i - 1], tangents[i]);\n\n          if (vec.length() > Number.EPSILON) {\n            vec.normalize();\n            const theta = Math.acos(THREE.MathUtils.clamp(tangents[i - 1].dot(tangents[i]), -1, 1)); // clamp for floating pt errors\n\n            normals[i].applyAxisAngle(new THREE.Vector3(0, 1, 0), theta);\n          }\n\n          binormals[i].crossVectors(tangents[i], normals[i]);\n        } // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same\n\n\n        if (closed === true) {\n          let theta = Math.acos(THREE.MathUtils.clamp(normals[0].dot(normals[segments]), -1, 1));\n          theta /= segments;\n\n          if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {\n            theta = -theta;\n          }\n\n          for (let i = 1; i <= segments; i++) {\n            // twist a little...\n            normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i));\n            binormals[i].crossVectors(tangents[i], normals[i]);\n          }\n        }\n\n        return {\n          tangents: tangents,\n          normals: normals,\n          binormals: binormals\n        };\n      });\n\n      this.rotationPitch = rotationPitch;\n    }\n\n  }\n\n  _exports.CustomEllipseCurve = CustomEllipseCurve;\n});","define(\"m08-2020/lib/ThreeExtensions/OutlinesGeometry\", [\"exports\", \"three\"], function (_exports, THREE) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.OutlinesGeometry = void 0;\n\n  class OutlinesGeometry extends THREE.Geometry {\n    constructor(geometry) {\n      super();\n      this.faceSplitFailed = false;\n      this.initGeometry(geometry);\n    }\n\n    initGeometry(geometry) {\n      let geometry2 = this.getGeometry(geometry);\n      this.vertices = geometry2.vertices;\n      this.faces = geometry2.faces;\n      this.splitFaces();\n    }\n\n    splitFaces() {\n      const DELTA = 1e-5;\n      const keys = ['a', 'b', 'c'];\n      let vertices = this.vertices;\n      let faces = this.faces;\n      let vertexDict = vertices.reduce((dictX, vertex, index) => {\n        if (vertex.x in dictX) dictX[vertex.x].push({\n          vertex,\n          index\n        });else {\n          dictX[vertex.x] = [];\n          dictX[vertex.x].push({\n            vertex,\n            index\n          });\n        }\n        return dictX;\n      }, {}); // for ( let keyX of Object.keys( vertexDict ) ) {\n      //   vertexDict[ keyX ] = vertexDict[ keyX ].reduce((dictY, vertexData) => {\n      //     if ( vertexData.vertex.y in dictY ) dictY[ vertexData.vertex.y ].push( vertexData );\n      //     else { dictY[ vertexData.vertex.y ] = []; dictY[ vertexData.vertex.y ].push( vertexData ) }\n      //     return dictY;\n      //   }, {});\n      //   for ( let keyY of Object.keys( vertexDict[ keyX ] ) ) {\n      //     vertexDict[ keyX ][ keyY ] = vertexDict[ keyX ][ keyY ].reduce((dictZ, vertexData) => {\n      //       if ( vertexData.vertex.z in dictZ ) dictZ[ vertexData.vertex.z ].push( vertexData );\n      //       else { dictZ[ vertexData.vertex.z ] = []; dictZ[ vertexData.vertex.z ].push( vertexData ) }\n      //       return dictZ;\n      //     }, {});\n      //   }\n      // }\n      // let sortedVertices = vertices\n      //                     .map(( vertex, index ) => {\n      //                       return { vertex, index };\n      //                     })\n      //                     .sort( ( a, b ) => a.vertex.x - b.vertex.x );\n\n      let sortedKeysX = Object.keys(vertexDict).sort((a, b) => parseFloat(a) - parseFloat(b));\n      let edge = [0, 0],\n          face;\n\n      for (let i = 0; i < faces.length; i++) {\n        face = faces[i];\n\n        EDGES_LOOP: for (let j = 0; j < 3; j++) {\n          edge[0] = face[keys[j]];\n          edge[1] = face[keys[(j + 1) % 3]];\n          let vertexOne = vertices[edge[0]];\n          let vertexTwo = vertices[edge[1]];\n          let lowerBound = findBoundIndex(vertexOne.x, sortedKeysX);\n          let upperBound = findBoundIndex(vertexTwo.x, sortedKeysX);\n          if (lowerBound > upperBound) [lowerBound, upperBound] = [upperBound, lowerBound];\n          lowerBound = Math.max(lowerBound - 2, 0);\n          upperBound = Math.min(upperBound + 2, sortedKeysX.length - 1);\n          let line = new THREE.Line3(vertexOne, vertexTwo); // for each vertex checks if it lies in the edge\n\n          for (let e = lowerBound; e < upperBound; e++) {\n            let keyX = sortedKeysX[e];\n\n            for (let vertexData of vertexDict[keyX]) {\n              let i = vertexData.index;\n              if (i === edge[0] || i === edge[1]) continue;\n              let v = vertexData.vertex;\n              let closestPoint = line.closestPointToPoint(v, true, new THREE.Vector3());\n\n              if (closestPoint.distanceTo(v) < DELTA && v.distanceTo(line.start) > DELTA && v.distanceTo(line.end) > DELTA) {\n                // mark the current face as splitted so that his cords won't be considered\n                face.splitted = true; // Add two new faces, created splitting the face in two\n\n                let faceOne = new THREE.Face3(i, face[keys[(j + 2) % 3]], face[keys[j % 3]], face.normal, face.color, face.materialIndex);\n                let faceTwo = new THREE.Face3(i, face[keys[(j + 2) % 3]], face[keys[(j + 1) % 3]], face.normal, face.color, face.materialIndex);\n                faces.push(faceOne);\n                faces.push(faceTwo);\n                break EDGES_LOOP;\n              }\n            }\n          }\n\n          if (face.splitted) break;\n        }\n      }\n    }\n\n    getGeometry(geometry) {\n      let geometry2;\n      if (geometry.isBufferGeometry) geometry2 = new THREE.Geometry().fromBufferGeometry(geometry);else geometry2 = geometry.clone();\n      geometry2.mergeVertices();\n      geometry2.computeFaceNormals();\n      return geometry2;\n    }\n\n  }\n\n  _exports.OutlinesGeometry = OutlinesGeometry;\n\n  function findBoundIndex(coord, array) {\n    let min = 0;\n    let max = array.length - 1;\n\n    while (min <= max) {\n      let mid = Math.floor((min + max) / 2);\n      if (array[mid] == coord) return mid;else if (parseFloat(array[mid]) > parseFloat(coord)) max = mid - 1;else min = mid + 1;\n    }\n\n    return 0;\n  }\n});","define(\"m08-2020/lib/ThreeExtensions/PlanarExtrusionPointsGenerator\", [\"exports\", \"three\", \"polybooljs\"], function (_exports, THREE, _polybooljs) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.PlanarExtrusionPointsGenerator = void 0;\n\n  class PlanarExtrusionPointsGenerator {\n    constructor(points2D, extrusionVector2D) {\n      this.extrudedPoints = [];\n      this.generateExtrudedPoints(points2D, extrusionVector2D);\n    }\n\n    generateExtrudedPoints(points2D, extrusionVector2D) {\n      let oldPoints = points2D.map(pt => pt.clone());\n      let newPoints = points2D.map(pt => pt.clone().add(extrusionVector2D));\n      let polyPts = this.getPolygonPoints(oldPoints, newPoints);\n      let segments = this.generateSegmentsFromPoints(polyPts);\n      let finalPolygon = this.uniteSegmentsAndReturnPolygon(segments);\n      let finalPoints = this.getPointsFromFinalPolygon(finalPolygon);\n      this.extrudedPoints.push(...finalPoints);\n    }\n\n    getPointsFromFinalPolygon(finalPolygon) {\n      return finalPolygon.regions[0].map(pt => new THREE.Vector3(pt[0], pt[1], 0));\n    }\n\n    uniteSegmentsAndReturnPolygon(segments) {\n      let finalSegments = segments[0];\n\n      for (let i = 1; i < segments.length; i++) {\n        let comb = _polybooljs.default.combine(finalSegments, segments[i]);\n\n        finalSegments = _polybooljs.default.selectUnion(comb);\n      }\n\n      return _polybooljs.default.polygon(finalSegments);\n    }\n\n    generateSegmentsFromPoints(pointsArr) {\n      return pointsArr.reduce((allSegments, currentPoints) => [...allSegments, _polybooljs.default.segments({\n        regions: [currentPoints.map(pt => [pt.x, pt.y])],\n        inverted: false\n      })], []);\n    }\n\n    getPolygonPoints(oldPoints, newPoints) {\n      const Z_AXIS = new THREE.Vector3(0, 0, 1);\n      let startPts = [...oldPoints, oldPoints[0].clone()];\n      let endPts = [...newPoints, newPoints[0].clone()];\n      let polyPts = [];\n      let segmentPoints;\n\n      for (let i = 0; i < startPts.length - 1; i++) {\n        segmentPoints = [startPts[i], startPts[i + 1], endPts[i], endPts[i + 1]];\n        segmentPoints = this.sortPoints(segmentPoints, Z_AXIS);\n        polyPts.push(segmentPoints);\n      }\n\n      return polyPts;\n    }\n\n    sortPoints(points, normal) {\n      let centerPoint = this.getCenterPoint(points);\n\n      let sortOrder = (a, b) => normal.dot(new THREE.Vector3().crossVectors(a.clone().sub(centerPoint), b.clone().sub(centerPoint)));\n\n      points.sort(sortOrder);\n      return points;\n    }\n\n    getCenterPoint(pointsArr) {\n      let length = pointsArr.length;\n      let centerPoint = pointsArr.reduce((finalVec, currentVec) => finalVec.add(currentVec), new THREE.Vector3()).multiplyScalar(1 / length);\n      return centerPoint;\n    }\n\n  }\n\n  _exports.PlanarExtrusionPointsGenerator = PlanarExtrusionPointsGenerator;\n});","define(\"m08-2020/lib/ThreeExtensions/PlanarRotationPointsGenerator\", [\"exports\", \"three\", \"polybooljs\", \"delaunator\", \"poly-decomp\", \"m08-2020/lib/WireframeGenerator\"], function (_exports, THREE, _polybooljs, _delaunator, PolyDecomp, _WireframeGenerator) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.PlanarRotationPointsGenerator = void 0;\n\n  class PlanarRotationPointsGenerator {\n    constructor(pointsToRotate, rotationParameters) {\n      this.rotatedPoints = [];\n      this.generateRotatedPoints(pointsToRotate, rotationParameters);\n    }\n\n    generateRotatedPoints(pointsToRotate, rotationParameters) {\n      const DETAIL = 64;\n      let {\n        rotationAngle,\n        rotationPitch\n      } = rotationParameters;\n      let numOfSegments = DETAIL * Math.abs(rotationAngle) / Math.PI;\n      let segmentRotation = rotationAngle / numOfSegments;\n      let polyPts2D = pointsToRotate.map(pt => [pt.x, pt.y]);\n      PolyDecomp.makeCCW(polyPts2D);\n      let convexPolygons = PolyDecomp.quickDecomp(polyPts2D);\n      let polygonSegments = [];\n      convexPolygons.forEach(polygon => {\n        let polyPts3D = polygon.map(pt => new THREE.Vector3(pt[0], pt[1], 0));\n        let rotatedPointsPolygons = this.getRotatedPointsPolygons(polyPts3D, numOfSegments, segmentRotation);\n        let decomposedPolySegments = rotatedPointsPolygons[0];\n\n        for (let i = 1; i < rotatedPointsPolygons.length; i++) {\n          let comb = _polybooljs.default.combine(decomposedPolySegments, rotatedPointsPolygons[i]);\n\n          decomposedPolySegments = _polybooljs.default.selectUnion(comb);\n        }\n\n        polygonSegments.push(decomposedPolySegments);\n      });\n      let finalPolygon = this.uniteSegmentsAndReturnPolygon(polygonSegments);\n      let finalPoints = this.getPointsFromFinalPolygon(finalPolygon);\n      this.rotatedPoints.push(...finalPoints);\n    }\n\n    getPointsFromFinalPolygon(finalPolygon) {\n      return finalPolygon.regions[0].map(pt => new THREE.Vector3(pt[0], pt[1], 0));\n    }\n\n    uniteSegmentsAndReturnPolygon(segments) {\n      let finalSegments = segments[0];\n\n      for (let i = 1; i < segments.length; i++) {\n        let comb = _polybooljs.default.combine(finalSegments, segments[i]);\n\n        finalSegments = _polybooljs.default.selectUnion(comb);\n      }\n\n      return _polybooljs.default.polygon(finalSegments);\n    }\n\n    getRotatedPointsPolygons(points, numOfSegments, segmentRotation) {\n      const Z_AXIS = new THREE.Vector3(0, 0, 1);\n      let rotatedPointsPolygons = [];\n      let previousPts = [...points];\n\n      for (let s = 0; s < numOfSegments; s++) {\n        let oldPoints = previousPts.map(pt => pt.clone());\n        let newPoints = previousPts.map(pt => pt.clone().applyAxisAngle(Z_AXIS, segmentRotation));\n        previousPts = newPoints.map(pt => pt.clone());\n        let pointsToGetEdges = [...oldPoints, ...newPoints];\n\n        for (let i = 0; i < oldPoints.length; i++) {\n          for (let j = 0.2; j < 1; j += 0.2) {\n            pointsToGetEdges.push(new THREE.Vector3().lerpVectors(oldPoints[i], newPoints[i], j));\n          }\n        }\n\n        let outerPoints = this.getOuterPointsFromPointCloud(pointsToGetEdges, Z_AXIS);\n        rotatedPointsPolygons.push(_polybooljs.default.segments({\n          regions: [outerPoints.map(pt => [pt.x, pt.y])],\n          inverted: false\n        }));\n      }\n\n      return rotatedPointsPolygons;\n    }\n\n    generateSegmentsFromPoints(pointsArr) {\n      return pointsArr.reduce((allSegments, currentPoints) => [...allSegments, _polybooljs.default.segments({\n        regions: [currentPoints.map(pt => [pt.x, pt.y])],\n        inverted: false\n      })], []);\n    }\n\n    getPolygonPoints(oldPoints, newPoints) {\n      const Z_AXIS = new THREE.Vector3(0, 0, 1);\n      let startPts = [...oldPoints, oldPoints[0].clone()];\n      let endPts = [...newPoints, newPoints[0].clone()];\n      let polyPts = [];\n      let segmentPoints;\n\n      for (let i = 0; i < startPts.length - 1; i++) {\n        segmentPoints = [startPts[i], startPts[i + 1], endPts[i], endPts[i + 1]];\n        segmentPoints = this.sortPoints(segmentPoints, Z_AXIS);\n        polyPts.push(segmentPoints);\n      }\n\n      return polyPts;\n    }\n\n    getOuterPointsFromPointCloud(points, zAxis) {\n      let linePairs = this.getOuterLinePairsFromPoints(points);\n      let outerPoints = linePairs.reduce((allPts, currentPair) => {\n        allPts.push(...currentPair);\n        return allPts;\n      }, []).reduce((filteredPts, currentPt, idx) => {\n        if (idx % 2) filteredPts.push(currentPt);\n        return filteredPts;\n      }, []);\n      outerPoints = this.sortPoints(outerPoints, zAxis);\n      return outerPoints;\n    }\n\n    getOuterLinePairsFromPoints(points) {\n      let facesDict = this.getFacesDictFromPoints(points);\n      let linePairs = [];\n\n      for (let [edgeIndices, facePair] of Object.entries(facesDict)) {\n        if (facePair.length !== 2) {\n          let verticesIdx = edgeIndices.split(\",\").map(val => parseInt(val));\n          let vectorOne = points[verticesIdx[0]];\n          let vectorTwo = points[verticesIdx[1]];\n          linePairs.push([vectorOne, vectorTwo]);\n        }\n      }\n\n      return linePairs;\n    }\n\n    getFacesDictFromPoints(points) {\n      let faces = this.getFacesFromPoints(points);\n      return new _WireframeGenerator.WireframeGenerator().getFacesDict(faces);\n    }\n\n    getFacesFromPoints(points) {\n      let delaunayFaces = _delaunator.default.from(points.map(p => [p.x, p.y])).triangles;\n\n      let faces = [];\n\n      for (let i = 0; i < delaunayFaces.length; i += 3) faces.push({\n        a: delaunayFaces[i],\n        b: delaunayFaces[i + 1],\n        c: delaunayFaces[i + 2]\n      });\n\n      return faces;\n    }\n\n    sortPoints(points, normal) {\n      let centerPoint = this.getCenterPoint(points);\n\n      let sortOrder = (a, b) => normal.dot(new THREE.Vector3().crossVectors(a.clone().sub(centerPoint), b.clone().sub(centerPoint)));\n\n      points.sort(sortOrder);\n      return points;\n    }\n\n    getCenterPoint(pointsArr) {\n      let length = pointsArr.length;\n      let centerPoint = pointsArr.reduce((finalVec, currentVec) => finalVec.add(currentVec), new THREE.Vector3()).multiplyScalar(1 / length);\n      return centerPoint;\n    }\n\n  }\n\n  _exports.PlanarRotationPointsGenerator = PlanarRotationPointsGenerator;\n});","define(\"m08-2020/lib/ThreeExtensions/RotatedGeometry\", [\"exports\", \"three\", \"three/src/extras/Earcut\", \"m08-2020/lib/Utils\"], function (_exports, THREE, _Earcut, _Utils) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.RotatedGeometry = void 0;\n  const utils = new _Utils.Utils(THREE);\n\n  class RotatedGeometry extends THREE.Geometry {\n    constructor(points, rotationData) {\n      super();\n      this.generateSelf(points, rotationData);\n    }\n\n    generateSelf(points, rotationData) {\n      const DETAIL = 64;\n      const NUM_OF_POINTS = points.length;\n      this.reveresePointsIfNeeded(points, rotationData);\n      let {\n        rotationPoint,\n        rotationAxis,\n        rotationAngle,\n        rotationPitch\n      } = rotationData;\n      let numOfSegments = DETAIL * Math.abs(rotationAngle) / (2 * Math.PI);\n      this.vertices.push(...points);\n      let orientationFront = getOrientation(points, rotationAxis, rotationPoint);\n      let crossVecFront = getCrossProduct(points, orientationFront);\n      let pitchVector = new THREE.Vector3();\n\n      for (let i = 0; i < numOfSegments; i++) {\n        for (let point of points) {\n          let rotatedPoint = new THREE.Vector3().copy(point).sub(rotationPoint).applyAxisAngle(rotationAxis, (i + 1) * rotationAngle / numOfSegments).add(rotationPoint).add(pitchVector.copy(rotationAxis).multiplyScalar((i + 1) * rotationPitch / numOfSegments / 2));\n          this.vertices.push(rotatedPoint);\n        }\n      }\n\n      let frontFaces = triangulatePoints3D(points, crossVecFront);\n      let backIndexStart = this.vertices.length - NUM_OF_POINTS;\n      let backPoints = this.vertices.slice(backIndexStart);\n      let backIndexMap = {};\n\n      for (let i = 0; i < backPoints.length; i++) backIndexMap[i] = backIndexStart + i;\n\n      let orientationBack = getOrientation(backPoints, rotationAxis, rotationPoint);\n      let crossVecBack = getCrossProduct(backPoints, orientationBack);\n      let backFaces = triangulatePoints3D(backPoints, crossVecBack);\n      if (crossVecFront.dot(crossVecBack) > 0) backFaces.reverse();\n\n      if (!pointsAreSameFrontBack(points, backPoints)) {\n        // Front\n        for (let i = 0, l = frontFaces.length; i < l; i += 3) {\n          this.faces.push(new THREE.Face3(frontFaces[i], frontFaces[i + 1], frontFaces[i + 2]));\n          addUV(this.faceVertexUvs[0]);\n        } // Back\n\n\n        for (let i = 0, l = backFaces.length; i < l; i += 3) {\n          this.faces.push(new THREE.Face3(backIndexMap[backFaces[i]], backIndexMap[backFaces[i + 1]], backIndexMap[backFaces[i + 2]]));\n          addUV(this.faceVertexUvs[0]);\n        }\n      } // Side\n\n\n      for (let s = 0; s < numOfSegments; s++) {\n        let offsetFromStart = s * NUM_OF_POINTS;\n\n        for (let i = 0; i < NUM_OF_POINTS; i++) {\n          let correctedIndexBack = i === NUM_OF_POINTS - 1 ? NUM_OF_POINTS : i + NUM_OF_POINTS + 1; // Bad naming/style?\n\n          let correctedIndexFront = i === NUM_OF_POINTS - 1 ? 0 : i + 1;\n          this.faces.push(new THREE.Face3(i + offsetFromStart, i + NUM_OF_POINTS + offsetFromStart, correctedIndexBack + offsetFromStart));\n          this.faces.push(new THREE.Face3(i + offsetFromStart, correctedIndexBack + offsetFromStart, correctedIndexFront + offsetFromStart));\n          addUV(this.faceVertexUvs[0]);\n          addUV(this.faceVertexUvs[0]);\n        }\n      }\n\n      this.computeFaceNormals();\n      this.computeVertexNormals();\n    }\n\n    reveresePointsIfNeeded(points, rotationData) {\n      let {\n        rotationPoint,\n        rotationAxis,\n        rotationAngle\n      } = rotationData;\n      let orientation = getOrientation(points, rotationAxis, rotationPoint);\n      let crossVec = getCrossProduct(points, orientation);\n      let extrusionDir = getExtrusionDirection(points[0], rotationPoint, rotationAxis, Math.sign(rotationAngle));\n      if (extrusionDir.dot(crossVec) < 0) points.reverse();\n    }\n\n  } // Helper functions\n\n\n  _exports.RotatedGeometry = RotatedGeometry;\n\n  function triangulatePoints3D(points, surfaceNormal) {\n    const Z_AXIS = new THREE.Vector3(0, 0, 1);\n    const QUATERNION = new THREE.Quaternion().setFromUnitVectors(surfaceNormal, Z_AXIS);\n    let dummyVec = new THREE.Vector3();\n    let pointsFlat = points.reduce((ptArr, pt) => {\n      dummyVec.copy(pt);\n      dummyVec.applyQuaternion(QUATERNION);\n      ptArr.push(dummyVec.x, dummyVec.y, dummyVec.z);\n      return ptArr;\n    }, []);\n\n    let faces = _Earcut.Earcut.triangulate(pointsFlat, [], 3);\n\n    if (surfaceNormal.dot(Z_AXIS) < 0) faces.reverse();\n    return faces;\n  }\n\n  function pointsAreSameFrontBack(frontPts, backPts) {\n    let allPointsAreEqual = true;\n\n    for (let i = 0; i < frontPts.length; i++) {\n      if (!utils.vectorsAreEqual(frontPts[i], backPts[i])) allPointsAreEqual = false;\n    }\n\n    return allPointsAreEqual;\n  }\n\n  function getExtrusionDirection(referencePoint, rotationPoint, rotationAxis, rotationSign) {\n    let rotatedPoint = new THREE.Vector3().copy(referencePoint).sub(rotationPoint).applyAxisAngle(rotationAxis, rotationSign * 0.1).add(rotationPoint);\n    return new THREE.Vector3().subVectors(rotatedPoint, referencePoint);\n  }\n\n  function getOrientation(points, rotationAxis, rotationPoint) {\n    let orientation = {\n      xAxis: getAxisX(points, rotationAxis, rotationPoint),\n      yAxis: rotationAxis\n    };\n    orientation.zAxis = new THREE.Vector3().crossVectors(orientation.xAxis, orientation.yAxis);\n    return orientation;\n  }\n\n  function getAxisX(points, rotationAxis, rotationPoint) {\n    let midVector = getMidVector(points);\n    let surfaceNormal = utils.getCrossVectorFromPoints(points);\n    let rotationPointCorrected = rotationPoint.clone().sub(midVector);\n    let rotPointOnSurface = rotationPointCorrected.clone().projectOnPlane(surfaceNormal);\n    let rotPointOnAxis = rotPointOnSurface.clone().projectOnVector(rotationAxis);\n    return rotPointOnSurface.sub(rotPointOnAxis).normalize();\n  }\n\n  function getMidVector(pts) {\n    let maxX = -Infinity;\n    let maxY = -Infinity;\n    let maxZ = -Infinity;\n    let minX = Infinity;\n    let minY = Infinity;\n    let minZ = Infinity;\n    pts.forEach(point => {\n      if (point.x > maxX) maxX = point.x;\n      if (point.y > maxY) maxY = point.y;\n      if (point.z > maxZ) maxZ = point.z;\n      if (point.x < minX) minX = point.x;\n      if (point.y < minY) minY = point.y;\n      if (point.z < minZ) minZ = point.z;\n    });\n    let midX = minX + (maxX - minX) / 2;\n    let midY = minY + (maxY - minY) / 2;\n    let midZ = minZ + (maxZ - minZ) / 2;\n    let midVector = new THREE.Vector3(midX, midY, midZ);\n    return midVector;\n  }\n\n  function getCrossProduct(points, orientation) {\n    let {\n      xAxis,\n      yAxis,\n      zAxis\n    } = orientation;\n    let ptA = new THREE.Vector3(0, 0, 0);\n    let minY = Infinity;\n    let maxX = -Infinity;\n    let idxA = 0;\n    let zProjection = new THREE.Vector3().copy(points[0]).projectOnVector(zAxis);\n    points.forEach((point, idx) => {\n      let projectedPoint = point.clone().sub(zProjection);\n      let projectedX = projectedPoint.dot(xAxis);\n      let projectedY = projectedPoint.dot(yAxis);\n\n      if (projectedY <= minY && projectedX >= maxX) {\n        minY = projectedY;\n        maxX = projectedX;\n        ptA.copy(projectedPoint);\n        idxA = idx;\n      }\n    });\n    let idxB = idxA === 0 ? points.length - 1 : idxA - 1;\n    let idxC = idxA === points.length - 1 ? 0 : idxA + 1;\n    let vecAB = new THREE.Vector3().subVectors(points[idxB], points[idxA]);\n    let vecAC = new THREE.Vector3().subVectors(points[idxC], points[idxA]);\n    return vecAB.cross(vecAC);\n  }\n\n  function addUV(UVs) {\n    // TEMP Func\n    UVs.push([new THREE.Vector2(0, 0), new THREE.Vector2(0, 0), new THREE.Vector2(0, 0)]);\n  }\n});","define(\"m08-2020/lib/ThreeModule\", [\"exports\", \"lodash\", \"three\", \"three/examples/jsm/controls/OrbitControls\", \"m08-2020/lib/CSGMesh\", \"polybooljs\", \"@tweenjs/tween.js\", \"m08-2020/lib/Utils\", \"m08-2020/lib/Utils/BooleanOperations\", \"m08-2020/lib/Utils/DimensionalChainIntersectionDetection\", \"m08-2020/lib/WireframeGenerator\", \"m08-2020/lib/ClippingUtils/SectionalPlane\", \"m08-2020/lib/ClippingUtils/DynamicSectionalPlane\", \"m08-2020/lib/FigureLoaders/DrawingObjectLoader\", \"m08-2020/lib/FigureLoaders/ArrowLoader\", \"m08-2020/lib/FigureLoaders/DimensionalChainLoader\", \"m08-2020/lib/FigureLoaders/FastenerLoader\", \"m08-2020/lib/FigureLoaders/DrawingPlaneLoader\", \"m08-2020/lib/DXFGenerator\", \"m08-2020/lib/ZoomController\"], function (_exports, lodash, THREE, _OrbitControls, _CSGMesh, _polybooljs, _tween, _Utils, BooleanOperations, _DimensionalChainIntersectionDetection, _WireframeGenerator, _SectionalPlane, _DynamicSectionalPlane, _DrawingObjectLoader, _ArrowLoader, _DimensionalChainLoader, _FastenerLoader, _DrawingPlaneLoader, _DXFGenerator, _ZoomController) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.GraphicsThree3D = void 0;\n\n  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n  class GraphicsThree3D {\n    //when clicked wireframe button here value changes\n    // Points for camera centering\n    // TODO: move intermediate points into specifice scope and leave only mid coords\n    constructor() {\n      _defineProperty(this, \"isWireFrameOnly\", false);\n\n      _defineProperty(this, \"fontUrlArray\", {\n        Regular: {\n          Arial: \"assets/fonts/Arial_Regular.json\",\n          Calibri: \"assets/fonts/Calibri_Regular.json\",\n          Courier: \"assets/fonts/Courier New_Regular.json\",\n          TimesNewRoman: \"assets/fonts/Times New Roman_Regular.json\"\n        },\n        Italic: {\n          Arial: \"assets/fonts/Arial_Italic.json\",\n          Calibri: \"assets/fonts/Calibri_Italic.json\",\n          Courier: \"assets/fonts/Courier New_Italic.json\",\n          TimesNewRoman: \"assets/fonts/Times New Roman_Italic.json\"\n        },\n        Bold: {\n          Arial: \"assets/fonts/Arial_Bold.json\",\n          Calibri: \"assets/fonts/Calibri_Bold.json\",\n          Courier: \"assets/fonts/Courier New_Bold.json\",\n          TimesNewRoman: \"assets/fonts/Times New Roman_Bold.json\"\n        },\n        BoldItalic: {\n          Arial: \"assets/fonts/Arial_Bold Italic.json\",\n          Calibri: \"assets/fonts/Calibri_Bold Italic.json\",\n          Courier: \"assets/fonts/Courier New_Bold Italic.json\",\n          TimesNewRoman: \"assets/fonts/Times New Roman_Bold Italic.json\"\n        }\n      });\n\n      _defineProperty(this, \"loadedFonts\", {});\n\n      _defineProperty(this, \"materialTransparentOptions\", null);\n\n      _defineProperty(this, \"interactiveZ\", false);\n\n      _defineProperty(this, \"extrusionVectorInteractiveZ\", null);\n\n      _defineProperty(this, \"initialPosition\", {\n        x: -50,\n        y: 50,\n        z: 100\n      });\n\n      _defineProperty(this, \"previousCameraPosition\", null);\n\n      _defineProperty(this, \"cameraTweenActive\", false);\n\n      _defineProperty(this, \"objectMaxX\", -Infinity);\n\n      _defineProperty(this, \"objectMaxY\", -Infinity);\n\n      _defineProperty(this, \"objectMaxZ\", -Infinity);\n\n      _defineProperty(this, \"objectMinX\", Infinity);\n\n      _defineProperty(this, \"objectMinY\", Infinity);\n\n      _defineProperty(this, \"objectMinZ\", Infinity);\n\n      _defineProperty(this, \"SceneCenterComputed\", false);\n\n      this.THREE = THREE;\n      this.OrbitControls = _OrbitControls.OrbitControls;\n      this.CSG = (0, _CSGMesh.CsgFactory)(THREE);\n      this.PolyBool = _polybooljs.default;\n      this.TWEEN = _tween.default;\n      this.canvasSize = {\n        width: 960,\n        height: 500\n      };\n      this.renderer = this.initRenderer(this.canvasSize);\n      this.camera = this.initCamera(this.canvasSize);\n      this.scene = new this.THREE.Scene();\n      this.scene.background = new this.THREE.Color(0xffffff);\n      this.stencilScenes = [];\n      this.controls = new this.OrbitControls(this.camera, this.renderer.domElement);\n      this.globalJSONData = {};\n      this.jsonData = {};\n      this.WireframeGenerator = new _WireframeGenerator.WireframeGenerator(this);\n      this.SectionalPlane = new _SectionalPlane.SectionalPlane(this);\n      this.DynamicSectionalPlane = new _DynamicSectionalPlane.DynamicSectionalPlane(this);\n      this.ThreeObjects = [];\n      this.objectMidVector = new this.THREE.Vector3(); /// Drawing Plane\n\n      this.transparencyControlObjects = {\n        area: [],\n        line: [],\n        point: [],\n        text: [],\n        volume: []\n      };\n      this.visualisationControlObjects = {\n        arrow: [],\n        dimensionalChain: [],\n        drawingObject: [],\n        fastener: []\n      }; ///\n\n      this.DimensionalChainIntersectionDetection = new _DimensionalChainIntersectionDetection.DimensionalChainIntersectionDetection();\n      this.dxfGenerator = new _DXFGenerator.DXFGenerator(this);\n      this.utils = new _Utils.Utils(THREE);\n      this.DrawingObjectLoader = new _DrawingObjectLoader.DrawingObjectLoader(this);\n      this.ArrowLoader = new _ArrowLoader.ArrowLoader(THREE, this.fontUrlArray, this);\n      this.DimensionalChainLoader = new _DimensionalChainLoader.DimensionalChainLoader(this);\n      this.FastenerLoader = new _FastenerLoader.FastenerLoader(THREE, this);\n      this.DrawingPlaneLoader = new _DrawingPlaneLoader.DrawingPlaneLoader(this);\n      this.ZoomController = new _ZoomController.ZoomController(this);\n      this.animate(this); ///\n      // this.renderer.domElement.style = \"position: absolute; width: 60%; height: 50%;\";\n      // this.scene.add( new this.THREE.AxesHelper( 10 ) );\n      ///\n    }\n\n    getGraphicsCanvas() {\n      return this.renderer.domElement;\n    }\n\n    initRenderer(canvasSize) {\n      let {\n        width,\n        height\n      } = canvasSize;\n      let renderer = new this.THREE.WebGLRenderer({\n        antialias: true,\n        preserveDrawingBuffer: true\n      });\n      renderer.setSize(width, height);\n      renderer.domElement.id = 'threeCanvas';\n      renderer.localClippingEnabled = true;\n      renderer.autoClear = false;\n      return renderer;\n    }\n\n    initCamera(canvasSize) {\n      const CAMERA_VIEW_SIZE = 5000;\n      const CAMERA_DEPTH = 5000;\n      const MULTIPLIER = 64;\n      let {\n        width,\n        height\n      } = canvasSize;\n      let cameraAspectRatio = width / height;\n      return new this.THREE.OrthographicCamera(CAMERA_VIEW_SIZE * cameraAspectRatio / -MULTIPLIER, CAMERA_VIEW_SIZE * cameraAspectRatio / MULTIPLIER, CAMERA_VIEW_SIZE / MULTIPLIER, CAMERA_VIEW_SIZE / -MULTIPLIER, -CAMERA_DEPTH, CAMERA_DEPTH);\n    }\n\n    makeTransparentClone(mesh) {\n      let transparentClone = new this.THREE.Mesh(); // transparentClone.applyMatrix4(mesh.matrix);\n\n      return transparentClone;\n    }\n\n    initWireframeObject(mesh, transparentMesh, jsonData, scene) {\n      let objectData = {\n        id: \"none\",\n        //TODO: Apply ID\n        data: jsonData,\n        sceneObject: mesh,\n        targetScene: scene\n      };\n\n      if (transparentMesh) {\n        mesh.IsCSGObject = true;\n        objectData.IsCSGObject = true;\n        objectData.sceneObjectTransparentCSG = transparentMesh;\n        objectData.type = \"polygon\"; // \"polygon\" is for wireframe to work // TODO: change it\n\n        mesh.customTypeName = \"polygon\";\n        transparentMesh.customTypeName = \"polygon\";\n      }\n\n      this.ThreeObjects.push(objectData);\n    }\n\n    makeWireframeFromPoints(points, extrusionVector, lineProps) {\n      const RENDER_ORDER = -99;\n      let wireframes = [];\n      let vectors = points.map(point => new this.THREE.Vector3(point.x, point.y, point.z));\n      let wireframe = this.utils.drawConnectedLines(vectors, lineProps, true);\n      wireframe.renderOrder = RENDER_ORDER;\n      wireframes.push(wireframe);\n      let wireframeClone = wireframe.clone();\n      wireframeClone.position.add(extrusionVector);\n      wireframes.push(wireframeClone);\n      wireframes.push(...this.drawWireframeSideLines(vectors, extrusionVector, lineProps));\n      return wireframes;\n    }\n\n    drawWireframeSideLines(points, extrusionVector, lineProps, renderOrder = -99) {\n      let sideLines = [];\n\n      for (let i = 0; i < points.length; i++) {\n        let indexThree = i + 2;\n        if (indexThree >= points.length) indexThree -= points.length;\n        let indexTwo = indexThree - 1;\n        if (indexTwo < 0) indexTwo += points.length;\n        let indexOne = indexTwo - 1;\n        if (indexOne < 0) indexOne += points.length;\n        let pointOne = points[indexOne].clone().normalize();\n        let pointTwo = points[indexTwo].clone().normalize();\n        let pointThree = points[indexThree].clone().normalize();\n        let vectorOne = pointTwo.clone().sub(pointOne);\n        let vectorTwo = pointThree.clone().sub(pointTwo);\n        const DELTA = 0.001;\n        let angleBetween = vectorOne.angleTo(vectorTwo);\n        if (angleBetween > Math.PI) angleBetween -= Math.PI;\n\n        if (angleBetween > Math.PI / 10 && angleBetween < Math.PI - DELTA) {\n          let pointOne = points[indexTwo];\n          let pointTwo = points[indexTwo].clone().add(extrusionVector);\n\n          if (pointOne.distanceTo(pointTwo) > 0) {\n            let sideLine = this.utils.drawConnectedLines([pointOne, pointTwo], lineProps);\n            sideLine.renderOrder = renderOrder;\n            sideLines.push(sideLine);\n          }\n        }\n      }\n\n      return sideLines;\n    }\n\n    makeWireframes(regions, extrusionVector, lineProps) {\n      let wireframes = [];\n      regions.forEach(region => {\n        let finalPolygons = region.positiveRegions.length > 0 || region.positiveRegions.length > 0 && region.negativeRegions.length > 0 ? BooleanOperations.makePolygonsFromPosAndNegRegions(region) : {\n          regions: []\n        };\n        finalPolygons.regions.forEach(polygonRegion => {\n          let vectors = polygonRegion.reduce((vectorArr, coords) => {\n            let newPoint = new this.THREE.Vector3(coords[0], coords[1], 0);\n            newPoint.applyEuler(region.eulerTwo);\n            newPoint.add(region.offsetVector);\n            vectorArr.push(newPoint);\n            return vectorArr;\n          }, []);\n          wireframes.push(...this.makeWireframeFromPoints(vectors, extrusionVector, lineProps));\n        });\n      });\n      return wireframes;\n    }\n\n    makePositionedExtrusion(geoData) {\n      let geometry = this.makeExtrudeGeoRaw(geoData.points2D, geoData.depth);\n      geometry.translate(...geoData.translation);\n      this.utils.skewExtrudedGeometry(geometry, geoData.skew);\n      return geometry;\n    }\n\n    makeExtrudeGeoRaw(points2D, depth) {\n      let shape = new this.THREE.Shape(points2D);\n      let extrudeSettings = {\n        depth,\n        bevelEnabled: false\n      };\n      let geometry = new this.THREE.ExtrudeGeometry(shape, extrudeSettings);\n      return geometry;\n    }\n\n    objectRotatesPlanar(objectData, isEllipse = false) {\n      let rotationAxis = this.utils.initVector3(objectData.objectGeneration.rotationAxis).normalize();\n      let crossVector;\n\n      if (isEllipse) {\n        let directionVectorOne = this.utils.initVector3(objectData.directionVector1);\n        let directionVectorTwo = this.utils.initVector3(objectData.directionVector2);\n        crossVector = this.utils.getCrossVector(directionVectorOne, directionVectorTwo);\n      } else {\n        let points = objectData.points;\n        crossVector = this.utils.getCrossVectorFromPoints(points);\n      }\n\n      return Math.abs(crossVector.dot(rotationAxis)) == 1;\n    }\n\n    objectExtrudesPlanar(objectData, isEllipse = false) {\n      let extrusionVector = this.utils.initVector3(objectData.objectGeneration.extrusionVector).normalize();\n      let crossVector;\n\n      if (isEllipse) {\n        let directionVectorOne = this.utils.initVector3(objectData.directionVector1);\n        let directionVectorTwo = this.utils.initVector3(objectData.directionVector2);\n        crossVector = this.utils.getCrossVector(directionVectorOne, directionVectorTwo);\n      } else {\n        let points = objectData.points;\n        crossVector = this.utils.getCrossVectorFromPoints(points);\n      }\n\n      return crossVector.dot(extrusionVector) == 0;\n    }\n\n    drawObject(jsonData) {\n      let drawingObjects = jsonData.drawingObjects;\n      drawingObjects.forEach(drawingObject => {\n        let components = drawingObject.components;\n        let properties = drawingObject.properties;\n        if (components.texts) this.loadTexts(properties.text, components.texts, jsonData, drawingObject.insertionPoints);\n        let isComplexVolume = this.utils.isComplexVolume(properties);\n        if (isComplexVolume) this.DrawingObjectLoader.drawComplexVolumes(drawingObject, jsonData);else this.DrawingObjectLoader.drawRegularObjects(drawingObject, jsonData);\n\n        if (components.sectionalPlanes) {\n          this.centerScene();\n          this.SceneCenterComputed = true;\n        }\n\n        if (drawingObject.dynamicSectionalPlanes) {\n          this.centerScene();\n          this.SceneCenterComputed = true;\n        }\n      });\n    }\n\n    addObjToTranspControl(object, type) {\n      switch (type) {\n        case \"area\":\n          this.transparencyControlObjects.area.push(object);\n          break;\n\n        case \"line\":\n          this.transparencyControlObjects.line.push(object);\n          break;\n\n        case \"point\":\n          this.transparencyControlObjects.point.push(object);\n          break;\n\n        case \"text\":\n          this.transparencyControlObjects.text.push(object);\n          break;\n\n        case \"volume\":\n          this.transparencyControlObjects.volume.push(object);\n          break;\n\n        default:\n          break;\n      }\n    }\n\n    addObjectToVisControl(object, type) {\n      switch (type) {\n        case \"arrow\":\n          this.visualisationControlObjects.arrow.push(object);\n          break;\n\n        case \"dimensionalChain\":\n          this.visualisationControlObjects.dimensionalChain.push(object);\n          break;\n\n        case \"drawingObject\":\n          this.visualisationControlObjects.drawingObject.push(object);\n          break;\n\n        case \"fastener\":\n          this.visualisationControlObjects.fastener.push(object);\n          break;\n\n        default:\n          break;\n      }\n    }\n\n    addObjectToScene(object, objectTransparent, insertionPoints, jsonData, transpType, visType, objectData = null) {\n      if (insertionPoints) insertionPoints.forEach(insertionPoint => {\n        let insertionVector = this.utils.initVector3(insertionPoint.insertionVector);\n        let newMaterial = object.material.length ? object.material.map(mat => mat.clone()) : object.material.clone();\n        let newObject = object.clone();\n        newObject.material = newMaterial;\n        newObject.onBeforeRender = object.onBeforeRender;\n        newObject.stencilNeeded = object.stencilNeeded ? object.stencilNeeded : false;\n        newObject.addToDXF = object.addToDXF ? object.addToDXF : false;\n        newObject.dxfLayer = object.dxfLayer ? object.dxfLayer : \"No Layer\";\n        let newObjectTransparent = objectTransparent ? objectTransparent.clone() : null;\n        copyObjectWireframes(newObject, object);\n        if (newObjectTransparent) copyObjectWireframes(newObjectTransparent, objectTransparent);\n        let rotationAngle = insertionPoint.rotationAngle;\n        let pivotPoint = new this.THREE.Object3D();\n\n        if (rotationAngle) {\n          pivotPoint.position.set(insertionPoint.rotationPoint.x, insertionPoint.rotationPoint.y, insertionPoint.rotationPoint.z);\n          pivotPoint.attach(newObject);\n          if (newObjectTransparent) pivotPoint.attach(newObjectTransparent);\n          rotationAngle = rotationAngle * Math.PI / 180;\n          let rotationAxis = this.utils.initVector3(insertionPoint.rotationAxis);\n          pivotPoint.rotateOnAxis(rotationAxis, rotationAngle);\n        } else {\n          pivotPoint.attach(newObject);\n          if (newObjectTransparent) pivotPoint.attach(newObjectTransparent);\n        }\n\n        pivotPoint.position.add(insertionVector);\n        pivotPoint.updateMatrixWorld();\n        let regularObject = pivotPoint.children[0];\n        let transparentObject = newObjectTransparent ? pivotPoint.children[1] : null;\n        pivotPoint.children.forEach(child => {\n          child.applyMatrix4(pivotPoint.matrixWorld);\n        });\n        regularObject.isDrawingObject = true; // Used for drawingPlanes\n\n        this.initWireframeObject(regularObject, transparentObject, jsonData, this.scene);\n        this.scene.add(regularObject); ///\n\n        this.ZoomController.getDrawingObjectWireframes(regularObject);\n        if (transparentObject) this.ZoomController.getDrawingObjectWireframes(transparentObject); ///\n\n        if (objectData && objectData.components.sectionalPlanes) this.SectionalPlane.addToSectionalPlanes(insertionPoint, regularObject, objectData);\n\n        if (objectData && objectData.dynamicSectionalPlanes) {\n          objectData.dynamicSectionalPlanes.forEach(planeID => {\n            this.DynamicSectionalPlane.sectionalPlanes.forEach(sectionalPlane => {\n              if (planeID === sectionalPlane.id) {\n                sectionalPlane.targets.drawingObjects.push({\n                  mesh: regularObject,\n                  clippingPlanes: objectData.dynamicSectionalPlanes\n                });\n              }\n            });\n          });\n        }\n\n        if (object.dxfPoints) object.dxfPoints.forEach(ptsData => {\n          ptsData.pointPairs.forEach(pair => pair.map(pt => pt.applyMatrix4(regularObject.matrix)));\n          this.dxfGenerator.wireframePoints.push(ptsData);\n        });\n        this.addObjToTranspControl(regularObject, transpType);\n        this.addObjectToVisControl(regularObject, visType);\n      });\n\n      function copyObjectWireframes(ObjectNew, objectOld) {\n        ObjectNew.children = objectOld.children.map(child => {\n          let childClone = child.clone();\n          if (child.needsZoomControl) childClone.needsZoomControl = true;\n          if (child.isLine) childClone.isLine = true;\n          if (child.pointsStartEnd) childClone.pointsStartEnd = child.pointsStartEnd;\n          return childClone;\n        });\n      }\n    }\n\n    getThreeSideFaceObjects(object) {\n      object.updateMatrixWorld();\n      let [doubleMaterial, frontMaterial, backMaterial] = this.getThreeSideFaceMaterials(object);\n      let geometry = object.geometry.clone();\n      let frontSideObject = new this.THREE.Mesh(geometry);\n      frontSideObject.applyMatrix4(object.matrix);\n      let backSideObject = new this.THREE.Mesh(geometry);\n      backSideObject.applyMatrix4(object.matrix);\n      let doubleSideObject = new this.THREE.Mesh(geometry);\n      doubleSideObject.applyMatrix4(object.matrix);\n      doubleSideObject = this.getPositionedObject(doubleSideObject, doubleMaterial);\n      frontSideObject = this.getPositionedObject(frontSideObject, frontMaterial);\n      backSideObject = this.getPositionedObject(backSideObject, backMaterial);\n      return [doubleSideObject, frontSideObject, backSideObject];\n    }\n\n    getPositionedObject(object, material) {\n      let bsp = this.CSG.fromMesh(object);\n      let result = this.CSG.toMesh(bsp, new this.THREE.Matrix4());\n      result.material = material;\n      return result;\n    }\n\n    getThreeSideFaceMaterials(object) {\n      let objectMaterial = object.material.length > 0 ? object.material.map(mat => {\n        let newMat = mat.clone();\n        return newMat;\n      }) : object.material.clone();\n      let frontMaterial;\n\n      if (object.material.length > 0) {\n        frontMaterial = objectMaterial.map(mat => {\n          let newMat = mat.clone();\n          newMat.side = this.THREE.FrontSide;\n          return newMat;\n        });\n      } else {\n        frontMaterial = objectMaterial.clone();\n        frontMaterial.side = this.THREE.FrontSide;\n      }\n\n      let backMaterial;\n\n      if (object.material.length > 0) {\n        backMaterial = objectMaterial.map(mat => {\n          let newMat = mat.clone();\n          newMat.side = this.THREE.BackSide;\n          return newMat;\n        });\n      } else {\n        backMaterial = objectMaterial.clone();\n        backMaterial.side = this.THREE.BackSide;\n      }\n\n      let doubleMaterial;\n\n      if (object.material.length > 0) {\n        doubleMaterial = objectMaterial.map(mat => {\n          let newMat = mat.clone();\n          newMat.side = this.THREE.DoubleSide;\n          return newMat;\n        });\n      } else {\n        doubleMaterial = objectMaterial.clone();\n        doubleMaterial.side = this.THREE.DoubleSide;\n      }\n\n      return [doubleMaterial, frontMaterial, backMaterial];\n    }\n\n    getTransformedObjects(objects, insertionPoint) {\n      let rotationAngle = insertionPoint.rotationAngle;\n      let insertionVector = this.utils.initVector3(insertionPoint.insertionVector);\n      let pivotPoint = new this.THREE.Object3D();\n      let newObjects = [];\n      objects.forEach(object => {\n        let newObject = object.clone();\n        newObject.onBeforeRender = object.onBeforeRender;\n        newObjects.push(newObject);\n      });\n\n      if (rotationAngle) {\n        pivotPoint.position.set(insertionPoint.rotationPoint.x, insertionPoint.rotationPoint.y, insertionPoint.rotationPoint.z);\n        newObjects.forEach(obj => pivotPoint.attach(obj));\n        rotationAngle = rotationAngle * Math.PI / 180;\n        let rotationAxis = this.utils.initVector3(insertionPoint.rotationAxis);\n        pivotPoint.rotateOnAxis(rotationAxis, rotationAngle);\n      } else newObjects.forEach(obj => pivotPoint.attach(obj));\n\n      pivotPoint.position.add(insertionVector);\n      pivotPoint.updateMatrixWorld();\n      newObjects.forEach(obj => obj.applyMatrix4(pivotPoint.matrixWorld));\n      return newObjects;\n    }\n\n    getlineMeshMaterial(properties) {\n      return properties && properties.line ? this.getMaterialFromColor(properties.line.color) : null;\n    }\n\n    getPointMaterial(properties) {\n      return properties && properties.point ? this.getMaterialFromColor(properties.point.color) : null;\n    }\n\n    getAreaMaterial(mesh, properties) {\n      let objectMaterial;\n\n      if (properties && properties.area) {\n        let colorProps = properties.area.color; ///\n\n        if (properties.area.hatching.type == 2) {\n          let orientationVector = this.utils.normalizeVector(properties.area.hatching.orientationVector);\n          let hatchSpacing = properties.area.hatching.factor;\n          let hatchColor = properties.area.hatching.color;\n          let hatchThickness = properties.area.hatching.thickness;\n          objectMaterial = this.makeCanvasMaterial(colorProps, hatchColor, orientationVector, hatchSpacing, hatchThickness); // TODO: might need to optimize this\n\n          let localClone = new this.THREE.Mesh(mesh.geometry.clone(), mesh.material.clone());\n          this.scene.add(localClone);\n          this.centerScene();\n          let objectWidth = this.objectMaxX - this.objectMinX;\n          let objectHeight = this.objectMaxY - this.objectMinY;\n          this.scene.remove(localClone); ///\n          // let maxDistance = Math.max(objectWidth, objectHeight);\n\n          objectMaterial.map.wrapS = objectMaterial.map.wrapT = this.THREE.RepeatWrapping;\n          objectMaterial.map.repeat.set(1 / objectWidth, 1 / objectHeight);\n          objectMaterial.map.offset.set(0.5, 0.5);\n        } else if (properties.area.hatching.type == 1) {\n          objectMaterial = this.getMaterialFromColor(colorProps);\n        } else {\n          objectMaterial = null;\n        } ///\n\n      } else {\n        objectMaterial = null;\n      }\n\n      return objectMaterial;\n    }\n\n    getVolumeMaterialsIndexFaces(mesh, properties) {\n      let objectMaterial;\n\n      if (properties && properties.volume && mesh.geometry.faces) {\n        let faceSideColor = properties.volume.color.faceSide;\n        let edgeSideColor = properties.volume.color.edgeSide;\n        let endSideColor = properties.volume.color.endSide;\n        let cutSideColor = properties.volume.color.cutSide;\n        let faceSideMaterial = this.getMaterialFromColor(faceSideColor);\n        let edgeSideMaterial = this.getMaterialFromColor(edgeSideColor);\n        let endSideMaterial = this.getMaterialFromColor(endSideColor);\n        let cutSideMaterial = this.getMaterialFromColor(cutSideColor);\n        objectMaterial = [faceSideMaterial, edgeSideMaterial, endSideMaterial, cutSideMaterial];\n        this.indexMeshFaces(mesh, properties);\n      } else {\n        objectMaterial = null;\n      }\n\n      return objectMaterial;\n    }\n\n    indexMeshFaces(mesh, properties) {\n      let faceSideNormal = this.utils.initVector3(properties.volume.faceSideNormalVector).normalize();\n      let grainDirection = this.utils.initVector3(properties.volume.layers[0].grainDirectionVector).normalize();\n      mesh.geometry.faces.forEach(face => {\n        if (Math.abs(face.normal.dot(faceSideNormal)) > 0.9999) {\n          face.materialIndex = 0;\n        } else if (Math.abs(face.normal.dot(grainDirection)) < 0.0001) {\n          face.materialIndex = 1;\n        } else if (Math.abs(face.normal.dot(grainDirection)) > 0.9999) {\n          face.materialIndex = 2;\n        } else {\n          face.materialIndex = 3;\n        }\n      });\n    }\n\n    centerScene() {\n      let box = new this.THREE.BoxHelper(this.scene, 0xffff00);\n      let boxVertices = this.utils.getVerticesFromBufferGeometry(box.geometry);\n      let bbox = new this.THREE.Box3().setFromPoints(boxVertices);\n      this.objectMaxX = bbox.max.x;\n      this.objectMaxY = bbox.max.y;\n      this.objectMaxZ = bbox.max.z;\n      this.objectMinX = bbox.min.x;\n      this.objectMinY = bbox.min.y;\n      this.objectMinZ = bbox.min.z;\n      let objectWidth = this.objectMaxX - this.objectMinX;\n      let objectHeight = this.objectMaxY - this.objectMinY;\n      let objectDepth = this.objectMaxZ - this.objectMinZ;\n      let objectMidX = this.objectMinX + objectWidth / 2;\n      let objectMidY = this.objectMinY + objectHeight / 2;\n      let objectMidZ = this.objectMinZ + objectDepth / 2;\n      this.objectMidVector.set(objectMidX, objectMidY, objectMidZ);\n      this.controls.target.copy(this.objectMidVector);\n      this.controls.update();\n      this.camera.position.set(this.initialPosition.x, this.initialPosition.y, this.initialPosition.z).add(this.objectMidVector);\n      this.camera.lookAt(this.objectMidVector);\n      this.camera.updateProjectionMatrix();\n    }\n\n    clearScene() {\n      this.clearGraphicsState();\n      this.DrawingObjectLoader.WireframeGenerator.clearWireframeState();\n      this.DynamicSectionalPlane.clearSectionalPlanes();\n      this.ZoomController.drawingObjectWireframes();\n\n      while (this.scene.children.length > 0) {\n        this.scene.remove(this.scene.children[this.scene.children.length - 1]);\n      }\n    }\n\n    clearGraphicsState() {\n      this.previousCameraPosition = null;\n      this.cameraTweenActive = false;\n      this.ThreeObjects = [];\n      this.objectMaxX = -Infinity;\n      this.objectMaxY = -Infinity;\n      this.objectMaxZ = -Infinity;\n      this.objectMinX = Infinity;\n      this.objectMinY = Infinity;\n      this.objectMinZ = Infinity;\n      this.SceneCenterComputed = false;\n      this.stencilScenes = [];\n      this.transparencyControlObjects = {\n        area: [],\n        line: [],\n        point: [],\n        text: [],\n        volume: []\n      };\n      this.visualisationControlObjects = {\n        arrow: [],\n        dimensionalChain: [],\n        drawingObject: [],\n        fastener: []\n      };\n      this.DimensionalChainIntersectionDetection.meshArr = [];\n    }\n\n    getRotationParameters(pts, extrusionNormalized) {\n      let midVector = this.getMidVector(pts);\n      let crossVector = this.getCrossVector(pts, extrusionNormalized);\n      let [eulerOne, eulerTwo] = this.utils.getEulerOneAndTwo(crossVector);\n      return [midVector, eulerOne, eulerTwo, crossVector];\n    }\n\n    getMidVector(pts) {\n      let maxX = -Infinity;\n      let maxY = -Infinity;\n      let maxZ = -Infinity;\n      let minX = Infinity;\n      let minY = Infinity;\n      let minZ = Infinity;\n      pts.forEach(point => {\n        if (point.x > maxX) maxX = point.x;\n        if (point.y > maxY) maxY = point.y;\n        if (point.z > maxZ) maxZ = point.z;\n        if (point.x < minX) minX = point.x;\n        if (point.y < minY) minY = point.y;\n        if (point.z < minZ) minZ = point.z;\n      });\n      let midX = minX + (maxX - minX) / 2;\n      let midY = minY + (maxY - minY) / 2;\n      let midZ = minZ + (maxZ - minZ) / 2;\n      let midVector = new this.THREE.Vector3(midX, midY, midZ);\n      return midVector;\n    }\n\n    getCrossVector(points, extrusionNormalized) {\n      let crossVector = this.utils.getCrossVectorFromPoints(points);\n      if (extrusionNormalized.dot(crossVector) < 0) crossVector.negate();\n      return crossVector;\n    }\n\n    getMaterialFromColor(colorProps) {\n      let {\n        color,\n        opacity\n      } = this.utils.getColorAndOpacity(colorProps);\n      let materialOptions = {\n        transparent: true,\n        color,\n        opacity,\n        side: this.THREE.DoubleSide\n      };\n      let material = new this.THREE.MeshBasicMaterial(materialOptions);\n      return material;\n    }\n\n    getVolumeMaterials(volumeColors) {\n      let faceSideColor = volumeColors.faceSide;\n      let edgeSideColor = volumeColors.edgeSide;\n      let endSideColor = volumeColors.endSide;\n      let cutSideColor = volumeColors.cutSide;\n      let faceSideMaterial = this.getMaterialFromColor(faceSideColor);\n      let edgeSideMaterial = this.getMaterialFromColor(edgeSideColor);\n      let endSideMaterial = this.getMaterialFromColor(endSideColor);\n      let cutSideMaterial = this.getMaterialFromColor(cutSideColor);\n      let materials = [faceSideMaterial, edgeSideMaterial, endSideMaterial, cutSideMaterial];\n      return materials;\n    }\n\n    indexVolumeFaces(geometry, faceSideNormal, grainDirection) {\n      geometry.faces.forEach(face => {\n        if (Math.abs(face.normal.dot(faceSideNormal)) == 1) {\n          face.materialIndex = 0;\n        } else if (face.normal.dot(grainDirection) == 0) {\n          face.materialIndex = 1;\n        } else if (Math.abs(face.normal.dot(grainDirection)) == 1) {\n          face.materialIndex = 2;\n        } else {\n          face.materialIndex = 3;\n        }\n      });\n    }\n\n    makeCircleWithEdges(radius, areaMaterial, borderMaterial, customParameters = null) {\n      let circleGeo;\n\n      if (customParameters) {\n        let thetaStart = customParameters.thetaStart;\n        let thetaEnd = customParameters.thetaEnd;\n        circleGeo = new this.THREE.CircleBufferGeometry(radius, 32, thetaStart, thetaEnd);\n        let radiusTwo = customParameters.radiusTwo;\n        circleGeo.applyMatrix4(new this.THREE.Matrix4().makeScale(1, radiusTwo / radius, 1));\n      } else {\n        circleGeo = new this.THREE.CircleBufferGeometry(radius, 32);\n      }\n\n      let areaMesh = new this.THREE.Mesh(circleGeo, areaMaterial);\n      let borderEdges = new this.THREE.EdgesGeometry(circleGeo);\n      let borderLine = new this.THREE.LineSegments(borderEdges, borderMaterial);\n      let circle = new this.THREE.Object3D();\n      circle.add(areaMesh);\n      circle.add(borderLine);\n      return circle;\n    }\n\n    makeArrow(radius, height, areaMaterial, borderMaterial) {\n      let coneGeo = new this.THREE.ConeBufferGeometry(radius, height, 32);\n      coneGeo.translate(0, -height / 2, 0);\n      let coneMesh = new this.THREE.Mesh(coneGeo, areaMaterial);\n      coneMesh.position.y = -height * 0.025;\n      let borderMesh = new this.THREE.Mesh(coneGeo, borderMaterial);\n      borderMesh.scale.multiplyScalar(1.05);\n      borderMesh.material.side = this.THREE.BackSide;\n      let cone = new this.THREE.Object3D();\n      cone.add(coneMesh);\n      cone.add(borderMesh);\n      return cone;\n    }\n\n    getLineMaterial(lineProps) {\n      let lineType = lineProps.type;\n      let lineColor = lineProps.color;\n      let lineMaterial;\n\n      if (lineType) {\n        if (lineType == 1) {\n          let materialOptions = {\n            color: \"rgb(\" + lineColor.red + \", \" + lineColor.green + \", \" + lineColor.blue + \")\",\n            transparent: true,\n            opacity: lineColor.alpha / 255\n          };\n          lineMaterial = new this.THREE.LineBasicMaterial(materialOptions);\n        } else {\n          lineMaterial = new this.THREE.LineDashedMaterial({\n            color: \"rgb(\" + lineColor.red + \", \" + lineColor.green + \", \" + lineColor.blue + \")\",\n            transparent: true,\n            opacity: lineColor.alpha / 255,\n            dashSize: lineType == 2 ? lineProps.factor : 0.2,\n            // TODO: might need to change this\n            gapSize: lineProps.factor ? lineProps.factor : 0\n          });\n        }\n      }\n\n      if (lineMaterial) lineMaterial.depthTest = false;else lineMaterial = new this.THREE.LineBasicMaterial({\n        transparent: true,\n        opacity: 0\n      });\n      return lineMaterial;\n    }\n\n    drawLine(pointOne, pointTwo, lineProps, forObjectGeneration = false) {\n      ///\n      // temporary solution. May be Fixed.\n      if (lineProps.type == 0 || lineProps.thickness == 0 || lineProps.color.alpha == 0) return new this.THREE.Mesh(); ///\n\n      let lineMaterial = this.getMaterialFromColor(lineProps.color);\n      let lineRadius = lineProps.thickness / 2;\n      let lineSize = pointOne.distanceTo(pointTwo);\n      let lineGeo = new this.THREE.CylinderGeometry(lineRadius, lineRadius, lineSize, 8);\n      lineGeo.rotateX(Math.PI / 2);\n      lineGeo.translate(0, 0, lineSize / 2); // if (!forObjectGeneration) lineGeo.merge(new this.THREE.SphereGeometry(lineRadius, 8, 8));\n\n      let lineMesh = new this.THREE.Mesh(lineGeo, lineMaterial);\n      lineMesh.position.copy(pointOne);\n      lineMesh.lookAt(pointTwo);\n      if (!forObjectGeneration) lineMesh.renderOrder = -101;\n      return lineMesh;\n    }\n\n    getEllipsePlanarPoints(ellipseData) {\n      const CIRCLE_DETAIL = 64;\n      let radiusOne = ellipseData.radius1;\n      let radiusTwo = ellipseData.radius2;\n      let segmentHeight = ellipseData.segmentHeight;\n      let directionVectorOne = this.utils.initVector3(ellipseData.directionVector1).normalize();\n      let directionVectorTwo = this.utils.initVector3(ellipseData.directionVector2).normalize();\n      let circleVertices = [];\n\n      if (!directionVectorOne.dot(directionVectorTwo)) {\n        let crossVector = new this.THREE.Vector3().crossVectors(directionVectorOne, directionVectorTwo).normalize();\n        let startAngle = 0;\n        let endAngle = 2 * Math.PI;\n\n        if (ellipseData.segmentVector1 && ellipseData.segmentVector2) {\n          let segmentVectorOne = this.utils.initVector3(ellipseData.segmentVector1).normalize();\n          let segmentVectorTwo = this.utils.initVector3(ellipseData.segmentVector2).normalize(); ///\n\n          let segmentCross = new this.THREE.Vector3().crossVectors(segmentVectorOne, segmentVectorTwo);\n          if (segmentCross.length() === 0) segmentCross = new this.THREE.Vector3().crossVectors(directionVectorOne, directionVectorTwo).normalize();\n          let segOneToSegTwo = Math.acos(this.utils.clampNum(segmentVectorOne.dot(segmentVectorTwo), -1, 1));\n\n          if (crossVector.dot(segmentCross) < 0) {\n            segOneToSegTwo = -segOneToSegTwo;\n          }\n\n          let dirOneToSegOne = Math.acos(directionVectorOne.dot(segmentVectorOne));\n          let dirSegCross = new this.THREE.Vector3().crossVectors(directionVectorOne, segmentVectorOne);\n\n          if (crossVector.dot(dirSegCross) < 0) {\n            dirOneToSegOne = 2 * Math.PI - dirOneToSegOne;\n          }\n\n          startAngle = dirOneToSegOne;\n          endAngle = dirOneToSegOne + segOneToSegTwo;\n        }\n\n        let transformMatrix = new this.THREE.Matrix4().set(directionVectorOne.x, directionVectorTwo.x, crossVector.x, 0, directionVectorOne.y, directionVectorTwo.y, crossVector.y, 0, directionVectorOne.z, directionVectorTwo.z, crossVector.z, 0, 0, 0, 0, 1);\n        let angleDelta = 2 * Math.PI / CIRCLE_DETAIL;\n        let epsilon = 0.01;\n        let partOne = [];\n        let partTwo = [];\n\n        for (let i = 0; i < 2 * Math.PI; i += angleDelta) {\n          let localStartAngle = startAngle;\n          let localEndAngle = endAngle;\n\n          if (localStartAngle < localEndAngle) {\n            if (localEndAngle > 2 * Math.PI) {\n              localEndAngle -= 2 * Math.PI; // if ((i >= -epsilon && i <= localEndAngle + epsilon) || (i >= localStartAngle - epsilon && i <= 2 * Math.PI + epsilon)) {\n              //   let newVector = new this.THREE.Vector3(radiusOne * Math.cos(i), radiusTwo * Math.sin(i), 0);\n              //   newVector.applyMatrix4(transformMatrix);\n              //   partOne.push(newVector);\n              // }\n\n              if (i >= -epsilon && i <= localEndAngle + epsilon) {\n                let newVector = new this.THREE.Vector3(radiusOne * Math.cos(i), radiusTwo * Math.sin(i), 0);\n                newVector.applyMatrix4(transformMatrix);\n                partTwo.push(newVector);\n              }\n\n              if (i >= localStartAngle - epsilon && i <= 2 * Math.PI + epsilon) {\n                let newVector = new this.THREE.Vector3(radiusOne * Math.cos(i), radiusTwo * Math.sin(i), 0);\n                newVector.applyMatrix4(transformMatrix);\n                partOne.push(newVector);\n              }\n            } else {\n              if (i >= localStartAngle - epsilon && i <= localEndAngle + epsilon) {\n                let newVector = new this.THREE.Vector3(radiusOne * Math.cos(i), radiusTwo * Math.sin(i), 0);\n                newVector.applyMatrix4(transformMatrix);\n                partOne.push(newVector);\n              }\n            }\n          } else {\n            if (localEndAngle < 0) {\n              localEndAngle = 2 * Math.PI + localEndAngle;\n\n              if (i >= localStartAngle - epsilon && i <= localEndAngle + epsilon) {\n                let newVector = new this.THREE.Vector3(radiusOne * Math.cos(i), radiusTwo * Math.sin(i), 0);\n                newVector.applyMatrix4(transformMatrix);\n                partOne.push(newVector);\n              }\n            } else {\n              if (i >= -epsilon && i <= localEndAngle + epsilon) {\n                let newVector = new this.THREE.Vector3(radiusOne * Math.cos(i), radiusTwo * Math.sin(i), 0);\n                newVector.applyMatrix4(transformMatrix);\n                partTwo.push(newVector);\n              }\n\n              if (i >= localStartAngle - epsilon && i <= 2 * Math.PI + epsilon) {\n                let newVector = new this.THREE.Vector3(radiusOne * Math.cos(i), radiusTwo * Math.sin(i), 0);\n                newVector.applyMatrix4(transformMatrix);\n                partOne.push(newVector);\n              }\n            }\n          }\n        }\n\n        circleVertices = partOne;\n        circleVertices.push(...partTwo);\n        let zeroVector = new this.THREE.Vector3(0, 0, 0);\n\n        if (ellipseData.segmentVector1 && ellipseData.segmentVector2) {\n          if (segmentHeight) {\n            let vectorOne = circleVertices[0].clone();\n            let vectorTwo = circleVertices[circleVertices.length - 1].clone();\n            let oneRadius = zeroVector.distanceTo(vectorOne);\n            let twoRadius = zeroVector.distanceTo(vectorTwo);\n            let midVector = circleVertices[Math.floor(circleVertices.length / 2)].clone();\n            let midRadius = zeroVector.distanceTo(midVector);\n            let planeNormal = midVector.clone().normalize();\n            let plane = new this.THREE.Plane(planeNormal); ///\n\n            let needToPushZero = false;\n            let distanceOne = plane.distanceToPoint(vectorOne);\n            let distanceTwo = plane.distanceToPoint(vectorTwo);\n\n            if (distanceOne < 0 && distanceTwo < 0) {\n              if (segmentHeight > midRadius) {\n                let heightDelta = segmentHeight - midRadius;\n                circleVertices.forEach(vertex => {\n                  if (-plane.distanceToPoint(vertex) > heightDelta) {\n                    vertex.markForDelete = true;\n                  }\n                });\n                circleVertices = circleVertices.filter(vertex => !vertex.markForDelete); ///\n\n                segmentHeight -= heightDelta;\n                let lengthOne = vectorOne.length();\n                let lengthTwo = vectorTwo.length();\n                let minRadius = Math.min(oneRadius, twoRadius);\n                oneRadius = minRadius;\n                twoRadius = minRadius;\n                vectorOne = vectorOne.normalize().multiplyScalar(lengthTwo);\n                vectorTwo = vectorTwo.normalize().multiplyScalar(lengthOne);\n                needToPushZero = true;\n              } else {\n                let heightDelta = segmentHeight - midRadius;\n                let vecOne = vectorTwo.clone().normalize().multiplyScalar(oneRadius);\n                let vecTwo = vectorOne.clone().normalize().multiplyScalar(twoRadius);\n                let localNormal = new this.THREE.Vector3().lerpVectors(vecOne, vecTwo, 0.5).normalize();\n                let localPlane = new this.THREE.Plane(localNormal);\n                circleVertices.forEach(vertex => {\n                  if (localPlane.distanceToPoint(vertex) > heightDelta) {\n                    vertex.markForDelete = true;\n                  }\n                });\n                circleVertices = circleVertices.filter(vertex => !vertex.markForDelete);\n                return circleVertices;\n              }\n            } ///\n\n\n            let differenceOne = Math.abs(plane.distanceToPoint(midVector)) - Math.abs(plane.distanceToPoint(vectorOne));\n            let differenceTwo = Math.abs(plane.distanceToPoint(midVector)) - Math.abs(plane.distanceToPoint(vectorTwo));\n            let segmentOne = Math.abs(segmentHeight - differenceOne);\n            let segmentTwo = Math.abs(segmentHeight - differenceTwo);\n            let proportionOne = 1 - segmentOne / midRadius;\n            let proportionTwo = 1 - segmentTwo / midRadius;\n            let proportion = Math.max(proportionOne, proportionTwo);\n            let firstPoint = vectorOne.clone().normalize().multiplyScalar(oneRadius * proportion);\n            let secondPoint = vectorTwo.clone().normalize().multiplyScalar(twoRadius * proportion);\n            circleVertices.unshift(firstPoint);\n            circleVertices.push(secondPoint); ///\n\n            if (needToPushZero) circleVertices.push(zeroVector);\n          } else {\n            circleVertices.push(zeroVector);\n          }\n        }\n      }\n\n      return circleVertices;\n    }\n\n    getRotationIndices(points, rotationVector, forEllipse = false) {\n      let addAngle = forEllipse ? 0 : Math.PI / 2;\n      let xAxis = new this.THREE.Vector3(1, 0, 0);\n      let pointsNum = points.length;\n      let startIndex = (addAngle + rotationVector.clone().normalize().angleTo(xAxis)) / (2 * Math.PI) * pointsNum;\n      let endIndex = (addAngle + Math.PI + rotationVector.clone().normalize().angleTo(xAxis)) / (2 * Math.PI) * pointsNum;\n\n      if (endIndex >= pointsNum) {\n        endIndex -= pointsNum;\n      }\n\n      startIndex = Math.floor(startIndex);\n      endIndex = Math.floor(endIndex);\n      return [startIndex, endIndex];\n    }\n\n    interpolateWithDistance(pointOne, pointTwo, distance) {\n      let difference = pointOne.distanceTo(pointTwo);\n      let points = [];\n\n      if (difference > distance) {\n        let proportion = difference / distance;\n\n        for (let i = 1; i < proportion; i++) {\n          let newPoint = new this.THREE.Vector3().lerpVectors(pointOne, pointTwo, i / proportion);\n          points.push(newPoint);\n        }\n      }\n\n      return points;\n    }\n\n    makeRotatedObjectWireframe(curvePoints, lineProps, rotationData, rotationObjectWireframes, forPolygon = false) {\n      let centerPoint = rotationData.positionPoint;\n      let rotationPitch = rotationData.rotationPitch;\n      let rotationAngle = rotationData.rotationAngle;\n      let rotationAxis = rotationData.rotationAxis; ///\n\n      let rotationPoints = curvePoints.map(point => point.clone()); ///\n\n      let renderOrders = [-99, -101];\n\n      for (let renderOrder of renderOrders) {\n        let startEdge = this.utils.drawConnectedLines(curvePoints, lineProps, true);\n        startEdge.renderOrder = renderOrder;\n        let endGeo = startEdge.geometry.clone();\n        rotationObjectWireframes.push(startEdge);\n        let endEdge = new this.THREE.Mesh(endGeo, startEdge.material);\n        endEdge.renderOrder = renderOrder;\n        rotationObjectWireframes.push(endEdge);\n        let yAxis = new this.THREE.Vector3(0, 1, 0);\n\n        if (!forPolygon) {\n          let edgeDetail = 64;\n          let numOfSegments = edgeDetail * Math.abs(rotationAngle / Math.PI / 2);\n          startEdge.rotateOnAxis(yAxis, Math.PI);\n          endEdge.rotateOnAxis(yAxis, Math.PI);\n          startEdge.geometry.translate(-centerPoint, 0, 0);\n          endEdge.rotateOnAxis(yAxis, -rotationAngle);\n          endEdge.geometry.translate(-centerPoint, -rotationPitch, 0);\n          let rotationPoints = curvePoints.map(point => point.clone().applyAxisAngle(yAxis, Math.PI));\n\n          for (let i = 0; i < rotationPoints.length; i++) {\n            let indexThree = i + 2;\n            if (indexThree >= rotationPoints.length) indexThree -= rotationPoints.length;\n            let indexTwo = indexThree - 1;\n            if (indexTwo < 0) indexTwo += rotationPoints.length;\n            let indexOne = indexTwo - 1;\n            if (indexOne < 0) indexOne += rotationPoints.length;\n            let pointOne = rotationPoints[indexOne].clone().normalize();\n            let pointTwo = rotationPoints[indexTwo].clone().normalize();\n            let pointThree = rotationPoints[indexThree].clone().normalize();\n            let vectorOne = pointTwo.clone().sub(pointOne);\n            let vectorTwo = pointThree.clone().sub(pointTwo);\n            let angleBetween = vectorOne.angleTo(vectorTwo);\n            if (angleBetween > Math.PI) angleBetween -= Math.PI;\n\n            if (angleBetween > Math.PI / 10) {\n              let localPoint = rotationPoints[indexTwo].clone();\n              let edgePoints = [];\n              localPoint.add(new this.THREE.Vector3(centerPoint, rotationPitch, 0));\n\n              for (let i = 0; i < numOfSegments + 1; i++) {\n                let newPoint = localPoint.clone().applyAxisAngle(yAxis, -i * rotationAngle / numOfSegments);\n                newPoint.sub(new this.THREE.Vector3(0, i * rotationPitch / numOfSegments, 0));\n                edgePoints.push(newPoint);\n              }\n\n              let edgeLine = this.utils.drawConnectedLines(edgePoints, lineProps);\n              edgeLine.renderOrder = renderOrder;\n              rotationObjectWireframes.push(edgeLine);\n            }\n          }\n        } else {\n          let edgeDetail = 32;\n          let numOfSegments = edgeDetail * Math.abs(rotationAngle / Math.PI / 2);\n          startEdge.geometry.translate(centerPoint, rotationPitch, 0);\n          endEdge.geometry.translate(centerPoint, 0, 0);\n          endEdge.rotateOnAxis(yAxis, -rotationAngle);\n          rotationPoints.forEach(point => {\n            let localPoint = point.clone();\n            let edgePoints = [];\n            localPoint.add(new this.THREE.Vector3(centerPoint, rotationPitch, 0));\n\n            for (let i = 0; i < numOfSegments + 1; i++) {\n              let newPoint = localPoint.clone().applyAxisAngle(yAxis, -i * rotationAngle / numOfSegments);\n              newPoint.sub(new this.THREE.Vector3(0, i * rotationPitch / numOfSegments, 0));\n              edgePoints.push(newPoint);\n            }\n\n            let edgeLine = this.utils.drawConnectedLines(edgePoints, lineProps);\n            edgeLine.renderOrder = renderOrder;\n            rotationObjectWireframes.push(edgeLine);\n          });\n        }\n      }\n    }\n\n    makeCanvasMaterial(areaColor, hatchColor, orientationVector, hatchSpacing, hatchThickness) {\n      const POSITION_PIXEL_RATIO = 10;\n      let canvasMaterial;\n\n      if (hatchSpacing && hatchThickness) {\n        let tangent = orientationVector.x / orientationVector.y;\n        let canvas = document.createElement(\"canvas\");\n        let ctx = canvas.getContext(\"2d\");\n        ctx.fillStyle = \"rgb(\" + areaColor.red + \", \" + areaColor.green + \", \" + areaColor.blue + \")\";\n        ctx.strokeStyle = \"rgb(\" + hatchColor.red + \", \" + hatchColor.green + \", \" + hatchColor.blue + \")\";\n        ctx.lineWidth = hatchThickness * POSITION_PIXEL_RATIO;\n        /**\n         * canvas defaults are\n         * width:  300px,\n         * height: 150px\n         */\n\n        let textureWidth = 300;\n        let textureHeight = 150;\n        ctx.fillRect(0, 0, textureWidth, textureHeight);\n        hatchSpacing += 2 * hatchThickness;\n        let correctedHatchSpacing = hatchSpacing * POSITION_PIXEL_RATIO;\n\n        for (let i = 0; i < (textureWidth + textureHeight) / correctedHatchSpacing; i++) {\n          // TODO: Might need to change logic\n          if (orientationVector.y == 0) {\n            ctx.beginPath();\n            ctx.moveTo(0, i * correctedHatchSpacing);\n            ctx.lineTo(300, i * correctedHatchSpacing);\n            ctx.closePath();\n            ctx.stroke();\n          } else if (orientationVector.x == 0) {\n            ctx.beginPath();\n            ctx.moveTo(i * correctedHatchSpacing, 0);\n            ctx.lineTo(i * correctedHatchSpacing, 150);\n            ctx.closePath();\n            ctx.stroke();\n          } else {\n            ctx.beginPath();\n            ctx.moveTo(i * correctedHatchSpacing * tangent, -5);\n            ctx.lineTo(-5, i * correctedHatchSpacing);\n            ctx.closePath();\n            ctx.stroke();\n          }\n        }\n\n        let canvasTexture = new this.THREE.CanvasTexture(canvas);\n        canvasMaterial = new this.THREE.MeshBasicMaterial({\n          map: canvasTexture,\n          side: this.THREE.DoubleSide\n        });\n      } else {\n        canvasMaterial = new this.THREE.MeshBasicMaterial({\n          color: new this.THREE.Color(`rgb(${areaColor.red}, ${areaColor.green}, ${areaColor.blue})`),\n          side: this.THREE.DoubleSide\n        });\n      }\n\n      return canvasMaterial;\n    }\n\n    loadTexts(textProps, texts, jsonData, insertionPoints) {\n      let font = this.loadFont(textProps);\n\n      if (font) {\n        let textArr = [];\n        texts.forEach(text => {\n          let newText = this.drawText(text, textProps, font);\n          newText.jsonID = text.id;\n          textArr.push(newText);\n        });\n        let positionedTexts = this.applyPositionAndRotation(textArr, insertionPoints);\n        positionedTexts.forEach(text => {\n          let objectInfo = {\n            id: text.jsonID,\n            data: jsonData,\n            sceneObject: text\n          };\n          this.ThreeObjects.push(objectInfo);\n          this.scene.add(text);\n        });\n      }\n    }\n\n    applyPositionAndRotation(meshArr, insertionPoints) {\n      let positionedMeshArr = [];\n      if (insertionPoints) insertionPoints.forEach(insertionPoint => {\n        let insertionVector = this.utils.initVector3(insertionPoint.insertionVector);\n        let rotationAngle = insertionPoint.rotationAngle;\n        let pivotPoint = new this.THREE.Object3D();\n\n        if (rotationAngle) {\n          pivotPoint.position.set(insertionPoint.rotationPoint.x, insertionPoint.rotationPoint.y, insertionPoint.rotationPoint.z);\n          meshArr.forEach(mesh => pivotPoint.attach(mesh.clone()));\n          rotationAngle = rotationAngle * Math.PI / 180;\n          let rotationAxis = this.utils.initVector3(insertionPoint.rotationAxis);\n          pivotPoint.rotateOnAxis(rotationAxis, rotationAngle);\n        } else {\n          meshArr.forEach(mesh => pivotPoint.attach(mesh.clone()));\n        }\n\n        pivotPoint.position.add(insertionVector);\n        pivotPoint.updateMatrixWorld();\n        pivotPoint.children.forEach(child => {\n          child.applyMatrix4(pivotPoint.matrixWorld);\n          positionedMeshArr.push(child);\n        });\n      });\n      return positionedMeshArr;\n    }\n\n    getFontUrl(textProps) {\n      let fontType = textProps.type;\n      let fontStyle = textProps.style;\n      let fontUrl = \"\";\n      let fontName = \"\";\n\n      if (fontStyle == 1) {\n        if (fontType == 1) {\n          fontUrl = this.fontUrlArray.Regular[\"Arial\"];\n          fontName = \"FONT_REGULAR_ARIAL\";\n        } else if (fontType == 2) {\n          fontUrl = this.fontUrlArray.Regular[\"Calibri\"];\n          fontName = \"FONT_REGULAR_CALIBRI\";\n        } else if (fontType == 3) {\n          fontUrl = this.fontUrlArray.Regular[\"Courier\"];\n          fontName = \"FONT_REGULAR_COURIER\";\n        } else if (fontType == 4) {\n          fontUrl = this.fontUrlArray.Regular[\"TimesNewRoman\"];\n          fontName = \"FONT_REGULAR_TIMESNEWROMAN\";\n        }\n      } else if (fontStyle == 2) {\n        if (fontType == 1) {\n          fontUrl = this.fontUrlArray.Italic[\"Arial\"];\n          fontName = \"FONT_ITALIC_ARIAL\";\n        } else if (fontType == 2) {\n          fontUrl = this.fontUrlArray.Italic[\"Calibri\"];\n          fontName = \"FONT_ITALIC_CALIBRI\";\n        } else if (fontType == 3) {\n          fontUrl = this.fontUrlArray.Italic[\"Courier\"];\n          fontName = \"FONT_ITALIC_COURIER\";\n        } else if (fontType == 4) {\n          fontUrl = this.fontUrlArray.Italic[\"TimesNewRoman\"];\n          fontName = \"FONT_ITALIC_TIMESNEWROMAN\";\n        }\n      } else if (fontStyle == 3) {\n        if (fontType == 1) {\n          fontUrl = this.fontUrlArray.Bold[\"Arial\"];\n          fontName = \"FONT_BOLD_ARIAL\";\n        } else if (fontType == 2) {\n          fontUrl = this.fontUrlArray.Bold[\"Calibri\"];\n          fontName = \"FONT_BOLD_CALIBRI\";\n        } else if (fontType == 3) {\n          fontUrl = this.fontUrlArray.Bold[\"Courier\"];\n          fontName = \"FONT_BOLD_COURIER\";\n        } else if (fontType == 4) {\n          fontUrl = this.fontUrlArray.Bold[\"TimesNewRoman\"];\n          fontName = \"FONT_BOLD_TIMESNEWROMAN\";\n        }\n      } else if (fontStyle == 4) {\n        if (fontType == 1) {\n          fontUrl = this.fontUrlArray.BoldItalic[\"Arial\"];\n          fontName = \"FONT_BOLD_ITALIC_ARIAL\";\n        } else if (fontType == 2) {\n          fontUrl = this.fontUrlArray.BoldItalic[\"Calibri\"];\n          fontName = \"FONT_BOLD_ITALIC_CALIBRI\";\n        } else if (fontType == 3) {\n          fontUrl = this.fontUrlArray.BoldItalic[\"Courier\"];\n          fontName = \"FONT_BOLD_ITALIC_COURIER\";\n        } else if (fontType == 4) {\n          fontUrl = this.fontUrlArray.BoldItalic[\"TimesNewRoman\"];\n          fontName = \"FONT_BOLD_ITALIC_TIMESNEWROMAN\";\n        }\n      }\n\n      return [fontUrl, fontName];\n    }\n\n    loadFont(textProps) {\n      let loadedFonts = this.loadedFonts;\n      let [fontUrl, fontName] = this.getFontUrl(textProps);\n      let storedFont = loadedFonts[fontName];\n      let loader = new this.THREE.FontLoader();\n      let font;\n\n      if (fontUrl) {\n        if (storedFont) {\n          font = storedFont;\n        } else {\n          $.ajax({\n            'async': false,\n            type: \"GET\",\n            url: fontUrl\n          }).then(function (dataFont) {\n            font = loader.parse(dataFont);\n            loadedFonts[fontName] = font;\n          });\n        }\n      }\n\n      return font;\n    }\n\n    getTextGeo(text, textProps, font) {\n      let textContent = text.content;\n      let fontSize = textProps.size;\n      let heightWidthRatio = textProps.heightWidthRatio;\n      let textGeo = new this.THREE.TextBufferGeometry(textContent, {\n        font: font,\n        size: fontSize,\n        height: 0.01,\n        curveSegments: 8\n      });\n      textGeo.scale(heightWidthRatio, 1, 1);\n      textGeo.computeBoundingBox();\n\n      switch (text.relativePosition) {\n        case 1:\n          textGeo.center();\n          break;\n\n        case 2:\n          textGeo.translate(0, -textGeo.boundingBox.min.y, 0);\n          break;\n\n        case 3:\n          textGeo.translate(0, -textGeo.boundingBox.max.y, 0);\n          break;\n\n        case 4:\n          textGeo.translate(-textGeo.boundingBox.max.x, -textGeo.boundingBox.max.y, 0);\n          break;\n\n        case 5:\n          textGeo.translate(-textGeo.boundingBox.max.x, -textGeo.boundingBox.min.y, 0);\n          break;\n\n        default:\n          textGeo.center();\n          break;\n      }\n\n      return textGeo;\n    }\n\n    drawText(text, textProps, font) {\n      let normalVector = this.utils.initVector3(text.normalVector);\n      let directionVector = this.utils.initVector3(text.directionVector);\n      let textMesh;\n\n      if (!normalVector.dot(directionVector) && normalVector.lengthSq() && directionVector.lengthSq()) {\n        let textInsertionPoint = text.insertionPoint;\n        let textGeo = this.getTextGeo(text, textProps, font);\n        let textMaterial = this.getMaterialFromColor(textProps.color);\n        textMesh = new this.THREE.Mesh(textGeo, textMaterial);\n        this.alignObjectWithVectors(textMesh, textInsertionPoint, normalVector, directionVector);\n      } else {\n        textMesh = new this.THREE.Mesh();\n      }\n\n      return textMesh;\n    }\n\n    alignObjectWithVectors(textMesh, textInsertionPoint, normalVector, directionVector) {\n      let newUpVector = new this.THREE.Vector3().crossVectors(normalVector, directionVector);\n      let dotProduct = textMesh.up.dot(newUpVector);\n      let rotationAngle = -Math.acos(dotProduct);\n      textMesh.rotateOnAxis(normalVector, rotationAngle);\n      textMesh.position.set(textInsertionPoint.x, textInsertionPoint.y, textInsertionPoint.z);\n      textMesh.up = newUpVector;\n      textMesh.lookAt(textMesh.position.clone().add(normalVector));\n    }\n\n    drawCustom(jsonDataGlobal) {\n      let jsonData = lodash.cloneDeep(jsonDataGlobal);\n      console.log(jsonData); // DynamicSectionalPlanesData is located in public directory\n\n      if (DynamicSectionalPlanesData) {\n        this.assignDynamicSectionalPlanes(jsonData, DynamicSectionalPlanesData);\n        this.DynamicSectionalPlane.initSectionalPlanes(DynamicSectionalPlanesData);\n      }\n\n      this.settingsModifyJSON(jsonData);\n      this.jsonData = jsonData;\n      if (jsonData.fasteners) this.FastenerLoader.drawFasteners();\n      if (jsonData.drawingObjects) this.drawObject(jsonData);\n      if (jsonData.arrows) jsonData.arrows.forEach(arrowData => {\n        let meshArray = this.ArrowLoader.drawArrows(arrowData);\n        meshArray.forEach(mesh => {\n          let drawnObject = new Object();\n          drawnObject.id = arrowData.id;\n          drawnObject.type = \"arrow\";\n          drawnObject.data = arrowData;\n          drawnObject.sceneObject = mesh;\n          drawnObject.isOnScene = mesh.IsHighLight ? false : true;\n          this.ThreeObjects.push(drawnObject);\n          if (!mesh.IsHighLight) this.scene.add(drawnObject.sceneObject);\n        });\n      });\n      if (jsonData.dimensionalChains) this.DimensionalChainLoader.drawDimensionalChains(jsonData.dimensionalChains);\n      this.SectionalPlane.applySectionalPlanes();\n      this.DynamicSectionalPlane.applySectionalPlanes();\n      if (!this.SceneCenterComputed) this.centerScene();\n      if (!this.stencilScenes.length) this.stencilScenes.push(this.scene);\n\n      if (this.isWireFrameOnly) {\n        this.isWireFrameOnly = false;\n        this.ToggleWireframe();\n      }\n    }\n\n    assignDynamicSectionalPlanes(jsonData, dynamicSectionalPlane) {\n      if (dynamicSectionalPlane.targets.drawingObjects && jsonData.drawingObjects) {\n        dynamicSectionalPlane.targets.drawingObjects.forEach(targetID => {\n          jsonData.drawingObjects.forEach(object => {\n            if (object.id === targetID) {\n              object.dynamicSectionalPlanes = object.dynamicSectionalPlanes ? object.dynamicSectionalPlanes : [];\n              object.dynamicSectionalPlanes.push(dynamicSectionalPlane.planeData.id);\n            }\n          });\n        });\n      }\n    }\n\n    settingsModifyJSON(jsonData) {\n      let settings = jsonData.settings;\n      this.fillPropsWithSettingProps(jsonData, settings, \"arrows\");\n      this.fillPropsWithSettingProps(jsonData, settings, \"dimensionalChains\");\n      this.fillPropsWithSettingProps(jsonData, settings, \"drawingObjects\");\n      this.fillPropsWithSettingProps(jsonData, settings, \"fasteners\");\n    }\n\n    fillPropsWithSettingProps(jsonData, settings, objType) {\n      let settingsType = objType.slice(0, objType.length - 1);\n      let objects = jsonData[objType];\n\n      if (settings[settingsType] && settings[settingsType].visualisation) {\n        let objectSettingProps = settings[settingsType].properties;\n        objects.forEach(obj => {\n          if (!obj.properties && objectSettingProps) obj.properties = objectSettingProps;else if (objectSettingProps) {\n            if (!obj.properties.area && objectSettingProps.area) obj.properties.area = objectSettingProps.area;\n            if (!obj.properties.line && objectSettingProps.line) obj.properties.line = objectSettingProps.line;\n            if (!obj.properties.text && objectSettingProps.text) obj.properties.text = objectSettingProps.text;\n            if (!obj.properties.volume && objectSettingProps.volume) obj.properties.volume = objectSettingProps.volume;\n            if (!obj.properties.point && objectSettingProps.point) obj.properties.point = objectSettingProps.point;\n            if (!obj.properties.intersectionArea && objectSettingProps.intersectionArea) obj.properties.intersectionArea = objectSettingProps.intersectionArea;\n            if (!obj.properties.intersectionLine && objectSettingProps.intersectionLine) obj.properties.intersectionLine = objectSettingProps.intersectionLine;\n            if (!obj.properties.fastener && objectSettingProps.fastener) obj.properties.fastener = objectSettingProps.fastener;\n            if (!obj.properties.axis && objectSettingProps.axis) obj.properties.axis = objectSettingProps.axis;\n            if (!obj.properties.addOn && objectSettingProps.addOn) obj.properties.addOn = objectSettingProps.addOn;\n          }\n        });\n      } else {\n        jsonData[objType] = null;\n      }\n    }\n\n    getMeshUpVector(mesh, direction) {\n      let upObject = new this.THREE.Object3D();\n      upObject.position.copy(mesh.up);\n      mesh.add(upObject);\n      mesh.lookAt(direction);\n      mesh.updateMatrixWorld();\n      let upVector = upObject.getWorldPosition(new this.THREE.Vector3());\n      return upVector;\n    }\n\n    removeObject(type) {\n      this.stencilScenes.forEach(scene => {\n        this.ThreeObjects.forEach(object => {\n          scene.children.forEach(child => {\n            if (object.type == type && object.sceneObject.uuid == child.uuid) {\n              object.isOnScene = false;\n              scene.remove(child);\n            }\n          });\n        });\n\n        for (let index = 0; index < 50; index++) {\n          //there may be more than one in that type and to remove all off them loop is needed\n          for (let i = 0; i < scene.children.length; i++) {\n            if (scene.children[i].customTypeName == type) {\n              scene.remove(scene.children[i]);\n\n              for (let to = 0; to < this.ThreeObjects.length; to++) {\n                if (this.ThreeObjects[to].type == type) {\n                  this.ThreeObjects[to].isOnScene = false;\n                }\n              }\n            }\n          }\n        }\n      });\n    }\n\n    removeObjectMaskette(XorY) {\n      // for (let index = 0; index < this.ThreeObjects.length; index++) {\n      //  if(this.ThreeObjects[index].type==\"maskette\"){\n      //     console.log(this.ThreeObjects[index]);\n      //  }\n      // }\n      for (let index = 0; index < 50; index++) {\n        //there may be more than one in that type and to remove all off them loop is needed\n        for (let i = 0; i < this.scene.children.length; i++) {\n          if (this.scene.children[i].customTypeName == \"maskette\" && this.scene.children[i].XorY == XorY) {\n            this.scene.remove(this.scene.children[i]);\n\n            for (let to = 0; to < this.ThreeObjects.length; to++) {\n              if (this.ThreeObjects[to].type == \"maskette\" && this.ThreeObjects[to].sceneObject.XorY == XorY) {\n                this.ThreeObjects[to].isOnScene = false;\n              }\n            }\n          }\n        }\n      }\n    }\n\n    redrawObject(type) {\n      var self = this;\n      console.log(type);\n      this.ThreeObjects.forEach(function (element) {\n        if (type == \"maskette\" && element.type == \"maskette\" && !element.isOnScene) {\n          // self.drawMaskette(element.data);\n          self.scene.add(element.sceneObject);\n          element.isOnScene = true;\n        }\n      });\n    }\n\n    redrawObjectMaskette(XorY) {\n      var self = this;\n      this.ThreeObjects.forEach(function (element) {\n        if (element.type == \"maskette\" && !element.isOnScene && element.sceneObject.XorY == XorY) {\n          if (self.interactiveZ && element.sceneObject.IsHighLight) {\n            self.scene.add(element.sceneObject);\n            element.isOnScene = true;\n          } else if (!self.interactiveZ && !element.sceneObject.IsHighLight) {\n            self.scene.add(element.sceneObject);\n            element.isOnScene = true;\n          }\n        }\n      });\n    }\n\n    redrawCSGObject(element) {\n      let targetScene = element.targetScene;\n\n      if (element.IsCSGObject && !element.isOnScene) {\n        if (!this.isWireFrameOnly) targetScene.add(element.sceneObject);else targetScene.add(element.sceneObjectTransparentCSG);\n        element.isOnScene = true;\n      }\n    }\n\n    highlightX(value) {\n      this.interactiveZ = true;\n      this.removeObjectMaskette(\"x\");\n      this.redrawObjectMaskette(\"x\");\n    }\n\n    highlightY(value) {\n      this.interactiveZ = true;\n      this.removeObjectMaskette(\"y\");\n      this.redrawObjectMaskette(\"y\");\n    } // TODO: Add highlighting for dimensional chains\n\n\n    highlightZ(extrusionVectorInteractiveZ) {\n      this.interactiveZ = true;\n      this.extrusionVectorInteractiveZ = extrusionVectorInteractiveZ; //this.removeObject(\"maskette\");\n      //this.redrawObject(\"maskette\");\n    }\n\n    clearXHighlight() {\n      this.interactiveZ = false;\n      this.removeObjectMaskette(\"x\");\n      this.redrawObjectMaskette(\"x\");\n    }\n\n    clearYHighlight() {\n      this.interactiveZ = false;\n      this.removeObjectMaskette(\"y\");\n      this.redrawObjectMaskette(\"y\");\n    }\n\n    clearZHighlight() {\n      this.interactiveZ = false;\n    }\n\n    degreeToRadians(degree) {\n      return degree * Math.PI / 180;\n    }\n\n    radiansToDegree(radian) {\n      return radian * 180 / Math.PI;\n    }\n\n    animate(that) {\n      this.updateRendererAndCamera(that.renderer, that.camera);\n      this.renderAllScenes(that);\n      window.requestAnimationFrame(function () {\n        that.animate(that);\n        that.TWEEN.update();\n      }); // setTimeout(() => {\n      //   that.animate(that)\n      //   that.TWEEN.update();\n      // }, 100);\n    }\n\n    renderAllScenes(GraphicsThree3D) {\n      GraphicsThree3D.renderer.clear();\n      GraphicsThree3D.stencilScenes.forEach(scene => {\n        GraphicsThree3D.renderer.render(scene, GraphicsThree3D.camera);\n        GraphicsThree3D.renderer.clearDepth();\n      });\n    }\n\n    updateRendererAndCamera(renderer, camera) {\n      let canvas = renderer.domElement;\n      let width = canvas.clientWidth;\n      let height = canvas.clientHeight;\n      let needResize = canvas.width !== width || canvas.height !== height || canvas.style.width !== width || canvas.style.height !== height;\n\n      if (needResize) {\n        renderer.setSize(width, height, false);\n        let multiplier = 64;\n        let cameraAspectRatio = width / height;\n        let cameraViewSize = 5000;\n        camera.left = -cameraViewSize * cameraAspectRatio / multiplier;\n        camera.right = cameraViewSize * cameraAspectRatio / multiplier;\n        camera.top = cameraViewSize / multiplier;\n        camera.bottom = -cameraViewSize / multiplier;\n        camera.updateProjectionMatrix();\n      }\n    }\n\n    makeCameraTween(direction, distance) {\n      let controls = this.controls;\n      let camera = this.camera;\n      let midVector = this.objectMidVector;\n      let currentPosition = {\n        x: camera.position.x,\n        y: camera.position.y,\n        z: camera.position.z,\n        zoom: camera.zoom\n      };\n      let currentTarget = {\n        x: controls.target.x,\n        y: controls.target.y,\n        z: controls.target.z\n      };\n      let finalTarget = {\n        x: midVector.x,\n        y: midVector.y,\n        z: midVector.z\n      };\n      let targetsNotEqual = currentPosition.x != finalTarget.x && currentPosition.y != finalTarget.y && currentPosition.z != finalTarget.z;\n\n      if (direction == \"x\" && this.previousCameraPosition == \"y\") {\n        currentPosition.z += 5;\n      }\n\n      let changePosition;\n      this.cameraTweenActive = true;\n\n      if (direction == \"initial\") {\n        changePosition = {\n          x: midVector.x + this.initialPosition.x,\n          y: midVector.y + this.initialPosition.y,\n          z: midVector.z + this.initialPosition.z\n        };\n      } else if (direction == \"x\") {\n        changePosition = {\n          x: midVector.x - distance,\n          y: midVector.y,\n          z: midVector.z\n        };\n      } else if (direction == \"y\") {\n        changePosition = {\n          x: midVector.x,\n          y: midVector.y + distance,\n          z: midVector.z + 5\n        };\n      } else if (direction == \"z\") {\n        changePosition = {\n          x: midVector.x,\n          y: midVector.y,\n          z: midVector.z + distance\n        };\n      } else {\n        throw new Error(\"No direction is defined for tweening\");\n      }\n\n      changePosition.zoom = 1;\n      let speed = 350;\n      let type = this.TWEEN.Easing.Cubic.InOut;\n      let global = this;\n      let tween = new this.TWEEN.Tween(currentPosition).to(changePosition, speed).easing(type).onUpdate(function () {\n        camera.position.set(currentPosition.x, currentPosition.y, currentPosition.z);\n        camera.zoom = currentPosition.zoom;\n        camera.lookAt(midVector);\n        camera.updateProjectionMatrix();\n        controls.update();\n      }).onComplete(function () {\n        if (direction == \"x\") global.previousCameraPosition = \"x\";\n\n        if (direction == \"y\") {\n          camera.position.z -= 5;\n          camera.lookAt(midVector);\n          camera.updateProjectionMatrix();\n          controls.update();\n          global.previousCameraPosition = \"y\";\n        }\n\n        if (direction == \"z\") global.previousCameraPosition = \"z\";\n        if (direction == \"initial\") global.previousCameraPosition = \"inital\";\n        global.cameraTweenActive = false;\n      });\n\n      if (targetsNotEqual) {\n        camera.zoom = 1;\n        let controlsTween = new this.TWEEN.Tween(currentTarget).to(finalTarget, speed).easing(type).onUpdate(function () {\n          controls.target.set(currentTarget.x, currentTarget.y, currentTarget.z - 0.01);\n          camera.up = new global.THREE.Vector3(0, 1, 0);\n          camera.lookAt(controls.target);\n          controls.update();\n        }).chain(tween);\n        controlsTween.start();\n      } else {\n        tween.start();\n      }\n    }\n\n    ChangeCameraPosition0() {\n      if (!this.cameraTweenActive) this.makeCameraTween(\"initial\");\n      this.interactiveZ = false;\n    }\n\n    ChangeCameraPosition1() {\n      this.interactiveZ = false;\n      if (!this.cameraTweenActive) this.makeCameraTween(\"x\", 150);\n    }\n\n    ChangeCameraPosition2() {\n      this.interactiveZ = false;\n      if (!this.cameraTweenActive) this.makeCameraTween(\"y\", 150);\n    }\n\n    ChangeCameraPosition3() {\n      this.interactiveZ = false;\n      if (!this.cameraTweenActive) this.makeCameraTween(\"z\", 150);\n    }\n\n    ToggleWireframe() {\n      this.isWireFrameOnly = !this.isWireFrameOnly;\n      this.removeObject(\"polygon\");\n      this.removeObject(\"ellipse\");\n      this.ThreeObjects.forEach(element => this.redrawCSGObject(element));\n    }\n\n    SendBase64PNGToServer() {\n      let posVector = this.objectMidVector;\n      let posVectorOne = posVector.clone().add(new this.THREE.Vector3(this.initialPosition.x, this.initialPosition.y, this.initialPosition.z));\n      let posVectorTwo = posVector.clone().sub(new this.THREE.Vector3(150, 0, 0));\n      let posVectorThree = posVector.clone().add(new this.THREE.Vector3(0, 150, 0));\n      let posVectorFour = posVector.clone().add(new this.THREE.Vector3(0, 0, 150));\n      this.changeCameraPositionAndDownloadPNG(posVectorOne, \"grafik1.png\");\n      this.removeObject(\"maskette\");\n      this.changeCameraPositionAndDownloadPNG(posVectorTwo, \"grafik2.png\");\n      this.changeCameraPositionAndDownloadPNG(posVectorThree, \"grafik3.png\");\n      this.redrawObject(\"maskette\");\n      this.changeCameraPositionAndDownloadPNG(posVectorFour, \"grafik4.png\");\n    }\n\n    changeCameraPositionAndDownloadPNG(posVector, fileName) {\n      this.camera.position.copy(posVector);\n      this.camera.lookAt(this.objectMidVector);\n      this.camera.updateProjectionMatrix();\n      this.controls.update();\n      this.renderAllScenes(this);\n      this.downloadAsPNGImage(fileName);\n    }\n\n    downloadAsPNGImage(fileName) {\n      var strMime = \"image/png\";\n      var imgData = this.renderer.domElement.toDataURL(strMime); //download image\n\n      var link = document.createElement('a');\n\n      if (typeof link.download === 'string') {\n        document.body.appendChild(link); //Firefox requires the link to be in the body\n\n        link.download = fileName;\n        link.href = imgData;\n        link.click();\n        document.body.removeChild(link); //remove the link when done\n      } else {\n        location.replace(uri);\n      }\n    }\n\n  }\n\n  _exports.GraphicsThree3D = GraphicsThree3D;\n});","define(\"m08-2020/lib/Utils\", [\"exports\", \"three/examples/jsm/lines/Line2\", \"three/examples/jsm/lines/LineMaterial\", \"three/examples/jsm/lines/LineGeometry\"], function (_exports, _Line, _LineMaterial, _LineGeometry) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.Utils = void 0;\n\n  class Utils {\n    constructor(three) {\n      this.THREE = three;\n    }\n\n    initVector2(vectorData) {\n      return new this.THREE.Vector2(vectorData.x, vectorData.y);\n    }\n\n    initVector3(vectorData) {\n      let vector = new this.THREE.Vector3(vectorData.x, vectorData.y, vectorData.z ? vectorData.z : 0);\n      return vector;\n    }\n\n    vectorsAreEqual(vecA, vecB) {\n      const DELTA = 1e-4;\n      return Math.abs(vecA.x - vecB.x) < DELTA && Math.abs(vecA.y - vecB.y) < DELTA && Math.abs(vecA.z - vecB.z) < DELTA;\n    }\n\n    addVectorObjects(vecOne, vecTwo) {\n      return {\n        x: vecOne.x + vecTwo.x,\n        y: vecOne.y + vecTwo.y,\n        z: vecOne.z + vecTwo.z\n      };\n    }\n\n    applyRotationToVector(vectorData, rotationParams) {\n      let rotationAngle = rotationParams.rotationAngle * Math.PI / 180;\n      let rotationAxis = this.initVector3(rotationParams.rotationAxis).normalize();\n      let rotationPoint = this.initVector3(rotationParams.rotationPoint);\n      let vector = this.initVector3(vectorData).sub(rotationPoint).applyAxisAngle(rotationAxis, rotationAngle).add(rotationPoint);\n      return vector;\n    }\n\n    normalizeVector(vector) {\n      let vectorLength = Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2) + Math.pow(vector.z, 2));\n      let normalizedVector = {\n        x: vector.x / vectorLength,\n        y: vector.y / vectorLength,\n        z: vector.z / vectorLength\n      };\n      return normalizedVector;\n    }\n\n    roundToDecimals(num, decimals = 1) {\n      let multiplier = Math.pow(10, decimals);\n      return Math.round(num * multiplier) / multiplier;\n    }\n\n    checkVectorsEquality(vectorOne, vectorTwo, precision = 2) {\n      return this.roundToDecimals(vectorOne.x, precision) === this.roundToDecimals(vectorTwo.x, precision) && this.roundToDecimals(vectorOne.y, precision) === this.roundToDecimals(vectorTwo.y, precision) && this.roundToDecimals(vectorOne.z, precision) === this.roundToDecimals(vectorTwo.z, precision);\n    }\n\n    getEulerOneAndTwo(crossVector) {\n      let quaternionOne = new this.THREE.Quaternion();\n      quaternionOne.setFromUnitVectors(crossVector, new this.THREE.Vector3(0, 0, 1));\n      let eulerOne = new this.THREE.Euler();\n      eulerOne.setFromQuaternion(quaternionOne);\n      let quaternionTwo = new this.THREE.Quaternion();\n      quaternionTwo.setFromUnitVectors(new this.THREE.Vector3(0, 0, 1), crossVector);\n      let eulerTwo = new this.THREE.Euler();\n      eulerTwo.setFromQuaternion(quaternionTwo);\n      return [eulerOne, eulerTwo];\n    }\n\n    getCrossVector(vecOne, vecTwo) {\n      return new this.THREE.Vector3().crossVectors(vecOne, vecTwo).normalize();\n    }\n\n    clampNum(num, min, max) {\n      return Math.min(Math.max(num, min), max);\n    }\n\n    getColorRGB(colorData) {\n      let color = \"rgb(\" + colorData.red + \", \" + colorData.green + \", \" + colorData.blue + \")\";\n      return color;\n    }\n\n    getMaterialFromColorProps(colorProps) {\n      let materialOptions = {\n        color: this.getColorRGB(colorProps),\n        transparent: true,\n        opacity: colorProps.alpha / 255,\n        side: this.THREE.DoubleSide\n      };\n      let material = new this.THREE.MeshBasicMaterial(materialOptions);\n      return material;\n    }\n\n    isComplexVolume(properties) {\n      return properties && properties.volume && properties.volume.type > 1;\n    }\n\n    skewExtrudedGeometry(geometry, [skewX, skewY]) {\n      geometry.applyMatrix4(new this.THREE.Matrix4().set(1, 0, skewX, 0, 0, 1, skewY, 0, 0, 0, 1, 0, 0, 0, 0, 1));\n    }\n\n    getSkewParams(extrusionVector) {\n      let extrusionNormalized = extrusionVector.clone().normalize();\n      let skewX = extrusionNormalized.x / extrusionNormalized.z;\n      let skewY = extrusionNormalized.y / extrusionNormalized.z;\n      return [skewX, skewY];\n    }\n\n    getVerticesFromBufferGeometry(geometry) {\n      let vertices = [];\n      let posAttr = geometry.attributes.position;\n\n      if (posAttr) {\n        for (let i = 0; i < posAttr.count; i++) {\n          vertices.push(new this.THREE.Vector3().fromBufferAttribute(posAttr, i));\n        }\n      }\n\n      return vertices;\n    }\n\n    mergeLinePoints(pairArr, lineDirection) {\n      pairArr.sort((pairOne, pairTwo) => pairTwo[0].clone().projectOnVector(lineDirection).lengthSq() - pairOne[0].clone().projectOnVector(lineDirection).lengthSq());\n      let startingLength = pairArr.length;\n      let previousLengthChanged = true;\n\n      while (previousLengthChanged) {\n        for (let i = 0; i < pairArr.length; i++) {\n          for (let j = i; j < pairArr.length; j++) {\n            let pairOne = pairArr[i];\n            let pairTwo = pairArr[j];\n\n            if (this.linesLayOnSamePlane(pairOne, pairTwo, lineDirection)) {\n              let mergedPair = this.mergeTwoLinePoints(pairOne, pairTwo, lineDirection);\n\n              if (mergedPair) {\n                pairArr[i] = mergedPair;\n                if (i !== j) pairArr.splice(j, 1);\n              }\n            }\n          }\n        }\n\n        if (pairArr.length === startingLength) previousLengthChanged = false;else startingLength = pairArr.length;\n      }\n\n      return pairArr;\n    }\n\n    mergeTwoLinePoints(pairOne, pairTwo, lineDirection) {\n      if (pairOne[0].equals(pairTwo[0]) && pairOne[1].equals(pairTwo[1])) return pairOne;\n      let pairOneSorted = [...pairOne].sort((a, b) => {\n        let projA = new this.THREE.Vector3().copy(a).projectOnVector(lineDirection);\n        let projB = new this.THREE.Vector3().copy(b).projectOnVector(lineDirection);\n        return projA.dot(lineDirection) - projB.dot(lineDirection);\n      });\n      let pairTwoSorted = [...pairTwo].sort((a, b) => {\n        let projA = new this.THREE.Vector3().copy(a).projectOnVector(lineDirection);\n        let projB = new this.THREE.Vector3().copy(b).projectOnVector(lineDirection);\n        return projA.dot(lineDirection) - projB.dot(lineDirection);\n      });\n      let projectedPoints = [...pairOneSorted, ...pairTwoSorted].sort((a, b) => {\n        let projA = new this.THREE.Vector3().copy(a).projectOnVector(lineDirection);\n        let projB = new this.THREE.Vector3().copy(b).projectOnVector(lineDirection);\n        return projA.dot(lineDirection) - projB.dot(lineDirection);\n      });\n      let minPoint = projectedPoints[0];\n      let [pOneL0, pOneL1] = [pairOneSorted[0].distanceTo(minPoint), pairOneSorted[1].distanceTo(minPoint)];\n      let [pTwoL0, pTwoL1] = [pairTwoSorted[0].distanceTo(minPoint), pairTwoSorted[1].distanceTo(minPoint)];\n      let merged;\n      if (pTwoL0 === pOneL0 && pTwoL1 === pOneL1) merged = pairTwoSorted;else if (pTwoL0 > pOneL0 && pTwoL1 < pOneL1) merged = pairOneSorted;else if (pOneL0 > pTwoL0 && pOneL1 < pTwoL1) merged = pairTwoSorted;else if (pTwoL0 <= pOneL0 && pTwoL1 >= pOneL0 && pTwoL1 <= pOneL1) merged = [pairTwoSorted[0], pairOneSorted[1]];else if (pTwoL0 >= pOneL0 && pTwoL0 <= pOneL1 && pTwoL1 >= pOneL1) merged = [pairOneSorted[0], pairTwoSorted[1]];else if (pTwoL0 >= pOneL1 && pTwoL0 <= pOneL0 && pTwoL1 <= pOneL1) merged = [pairOneSorted[0], pairTwoSorted[1]];else if (pTwoL0 >= pOneL0 && pTwoL1 <= pOneL0 && pTwoL1 >= pOneL1) merged = [pairTwoSorted[0], pairOneSorted[1]];\n      return merged;\n    }\n\n    linesLayOnSamePlane(pairOne, pairTwo, planeNormal) {\n      const DELTA = 0.0001;\n      let projectionOne = pairOne[0].clone().projectOnPlane(planeNormal);\n      let projectionTwo = pairTwo[0].clone().projectOnPlane(planeNormal);\n      return projectionOne.distanceTo(projectionTwo) < DELTA;\n    }\n\n    getCrossVectorFromPoints(points) {\n      let pointVectors = [];\n\n      for (let i = 0; i < points.length - 1; i++) {\n        pointVectors.push(new this.THREE.Vector3().subVectors(points[i + 1], points[i]));\n      }\n\n      pointVectors.push(new this.THREE.Vector3().subVectors(points[0], points[points.length - 1]));\n      let crossVector = new this.THREE.Vector3();\n\n      for (let i = 0; i < pointVectors.length - 1; i++) {\n        crossVector.add(new this.THREE.Vector3().crossVectors(pointVectors[i], pointVectors[i + 1]));\n      }\n\n      crossVector.add(new this.THREE.Vector3().crossVectors(pointVectors[pointVectors.length - 1], pointVectors[0]));\n      crossVector.normalize();\n      return crossVector;\n    }\n\n    vectorIsZero(vectorData) {\n      return !vectorData.x && !vectorData.y && !vectorData.z;\n    }\n\n    drawLine(pointOne, pointTwo, lineProps) {\n      if (lineProps.type === 0 || lineProps.thickness === 0 || lineProps.color.alpha === 0) return new this.THREE.Mesh();\n      let lineMaterial = this.getMaterialFromColorProps(lineProps.color);\n      let lineRadius = lineProps.thickness / 2;\n      let lineSize = pointOne.distanceTo(pointTwo);\n      let lineGeo = new this.THREE.CylinderGeometry(lineRadius, lineRadius, lineSize, 8);\n      lineGeo.rotateX(Math.PI / 2);\n      lineGeo.translate(0, 0, lineSize / 2);\n      let lineMesh = new this.THREE.Mesh(lineGeo, lineMaterial);\n      lineMesh.position.copy(pointOne);\n      lineMesh.lookAt(pointTwo);\n      return lineMesh;\n    }\n\n    drawSolidLine(points, lineProps, closed = false) {\n      let lineMeshArray = [];\n      let localPoints = points.map(pt => pt.clone());\n      if (closed) localPoints.push(localPoints[0].clone());\n\n      for (let i = 0; i < localPoints.length - 1; i++) {\n        if (localPoints[i].distanceTo(localPoints[i + 1]) > 0) {\n          let lineMesh = this.drawLine(localPoints[i], localPoints[i + 1], lineProps, true);\n          lineMeshArray.push(lineMesh);\n        }\n      }\n\n      let firstLine = lineMeshArray.length > 0 ? lineMeshArray.splice(0, 1)[0] : new this.THREE.Mesh();\n      let lineMaterial = firstLine.material;\n      firstLine.updateMatrixWorld();\n      firstLine.geometry.applyMatrix4(firstLine.matrixWorld);\n\n      for (let i = 0; i < lineMeshArray.length; i++) {\n        lineMeshArray[i].updateMatrixWorld();\n        lineMeshArray[i].geometry.applyMatrix4(lineMeshArray[i].matrixWorld);\n        firstLine.geometry.merge(lineMeshArray[i].geometry);\n      }\n\n      firstLine = new this.THREE.Mesh(firstLine.geometry, lineMaterial);\n      return firstLine;\n    }\n\n    drawDashedLine(pointOne, pointTwo, factor, pointPairs) {\n      let newSegment = true;\n      let direction = new this.THREE.Vector3().subVectors(pointTwo, pointOne).normalize();\n      let distance = pointOne.distanceTo(pointTwo);\n      let segmentSize = factor;\n\n      while (distance > segmentSize) {\n        let newPoint = new this.THREE.Vector3().copy(pointOne).add(direction.clone().multiplyScalar(segmentSize));\n        if (newSegment) pointPairs.push([pointOne, newPoint]);\n        pointOne = newPoint;\n        distance -= segmentSize;\n        newSegment = !newSegment;\n      }\n    }\n\n    makeDashSegments(points, factor) {\n      let distanceDelta = factor;\n\n      for (let i = 0; i < points.length - 1; i++) {\n        let distance = points[i].distanceTo(points[i + 1]);\n\n        if (distance < distanceDelta) {\n          distanceDelta -= distance;\n        } else {\n          let newPoint = new this.THREE.Vector3().lerpVectors(points[i], points[i + 1], distanceDelta / distance);\n          newPoint.insertedPoint = true;\n          points.splice(i + 1, 0, newPoint);\n          distanceDelta = factor;\n        }\n      }\n    }\n\n    mergeLines(pointPairs, lineProps) {\n      let lineMeshArray = [];\n      pointPairs.forEach(pair => {\n        if (pair[0].distanceTo(pair[1]) > 0) {\n          let lineMesh = this.drawLine(pair[0], pair[1], lineProps);\n          lineMeshArray.push(lineMesh);\n        }\n      });\n      let firstLine = lineMeshArray.splice(0, 1)[0];\n      let lineMaterial = firstLine.material;\n      firstLine.updateMatrixWorld();\n      firstLine.geometry.applyMatrix4(firstLine.matrixWorld);\n\n      for (let i = 0; i < lineMeshArray.length; i++) {\n        lineMeshArray[i].updateMatrixWorld();\n        lineMeshArray[i].geometry.applyMatrix4(lineMeshArray[i].matrixWorld);\n        firstLine.geometry.merge(lineMeshArray[i].geometry);\n      }\n\n      firstLine = new this.THREE.Mesh(firstLine.geometry, lineMaterial);\n      return firstLine;\n    }\n\n    drawConnectedLines(points, lineProps, closed = false) {\n      let localPoints = points.map(point => point.clone());\n      let firstLine;\n\n      if (canDrawLine(lineProps)) {\n        if (canDrawSolidLine(lineProps)) {\n          firstLine = this.drawSolidLine(points, lineProps, closed);\n        } else if (canDrawDashedLine(lineProps)) {\n          let factor = lineProps.factor;\n          let pointPairs = [];\n          let segmentSize = factor;\n          if (closed) localPoints.push(localPoints[0].clone());\n          let bigSegmentPts = [];\n          let smallSegmentPts = [];\n\n          for (let p = 0; p < localPoints.length - 1; p++) {\n            let distance = localPoints[p].distanceTo(localPoints[p + 1]);\n\n            if (distance > factor) {\n              bigSegmentPts.push(localPoints[p]);\n              bigSegmentPts.push(localPoints[p + 1]);\n            } else {\n              smallSegmentPts.push(localPoints[p]);\n              smallSegmentPts.push(localPoints[p + 1]);\n            }\n          }\n\n          for (let p = 0; p < bigSegmentPts.length - 1; p++) {\n            let distance = bigSegmentPts[p].distanceTo(bigSegmentPts[p + 1]);\n            if (distance > segmentSize) this.drawDashedLine(bigSegmentPts[p], bigSegmentPts[p + 1], factor, pointPairs);else segmentSize -= segmentSize - distance;\n          }\n\n          this.makeDashSegments(smallSegmentPts, factor);\n          let newSegment = true;\n\n          for (let p = 0; p < smallSegmentPts.length - 1; p++) {\n            if (smallSegmentPts[p].insertedPoint) newSegment = !newSegment;\n            if (newSegment) pointPairs.push([smallSegmentPts[p], smallSegmentPts[p + 1]]);\n          }\n\n          firstLine = this.mergeLines(pointPairs, lineProps);\n        } else if (canDrawDottedLine(lineProps)) {\n          let lineMaterial = this.getMaterialFromColorProps(lineProps.color);\n          let factor = lineProps.factor;\n          let radius = lineProps.thickness / 2;\n          let circleGeos = [];\n          let segmentSize = factor;\n\n          if (closed) {\n            localPoints.push(localPoints[0].clone());\n          } ///\n\n\n          let bigSegmentPts = [];\n          let smallSegmentPts = [];\n\n          for (let p = 0; p < localPoints.length - 1; p++) {\n            let distance = localPoints[p].distanceTo(localPoints[p + 1]);\n\n            if (distance > factor) {\n              bigSegmentPts.push(localPoints[p]);\n              bigSegmentPts.push(localPoints[p + 1]);\n            } else {\n              smallSegmentPts.push(localPoints[p]);\n              smallSegmentPts.push(localPoints[p + 1]);\n            }\n          }\n\n          this.makeDashSegments(smallSegmentPts, factor); ///\n\n          smallSegmentPts.forEach(point => {\n            if (point.insertedPoint) {\n              let circle = new this.THREE.SphereGeometry(radius, 8, 8);\n              circle.translate(point.x, point.y, point.z);\n              circleGeos.push(circle);\n            }\n          });\n\n          for (let p = 0; p < bigSegmentPts.length - 1; p++) {\n            let distance = bigSegmentPts[p].distanceTo(bigSegmentPts[p + 1]);\n\n            if (distance > 0) {\n              if (distance > segmentSize) {\n                let numOfSegments = Math.floor(distance / segmentSize);\n\n                for (let i = 0; i < numOfSegments; i++) {\n                  let newPoint = new this.THREE.Vector3().lerpVectors(bigSegmentPts[p], bigSegmentPts[p + 1], i / numOfSegments);\n                  let circle = new this.THREE.SphereGeometry(radius, 8, 8);\n                  circle.translate(newPoint.x, newPoint.y, newPoint.z);\n                  circleGeos.push(circle);\n                  if (segmentSize < factor) segmentSize = factor;\n                }\n              } else {\n                segmentSize -= segmentSize - distance;\n              }\n            }\n          }\n\n          let firstCircle = circleGeos.splice(0, 1)[0];\n          circleGeos.forEach(circle => firstCircle.merge(circle));\n          firstLine = new this.THREE.Mesh(firstCircle, lineMaterial);\n        }\n      } else firstLine = new this.THREE.Mesh();\n\n      return firstLine; // Helper functions -->\n\n      function canDrawLine(lineProps) {\n        return lineProps.thickness && lineProps.color.alpha && (lineProps.type || lineProps.type === undefined);\n      }\n\n      function canDrawSolidLine(lineProps) {\n        return lineProps.type === 1 || lineProps.type === undefined || lineProps.factor === 0 && lineProps.type !== null && lineProps.type !== 0;\n      }\n\n      function canDrawDashedLine(lineProps) {\n        return lineProps.type === 2;\n      }\n\n      function canDrawDottedLine(lineProps) {\n        return lineProps.type === 3;\n      } // <-- Helper functions\n\n    }\n\n    drawFatLine(pointsArr, lineProps) {\n      const MIN_THICKNESS = 0.002;\n      let thickness = lineProps.thickness * 5e-3;\n      let {\n        color,\n        opacity\n      } = this.getColorAndOpacity(lineProps.color);\n      let lineGeoPoints = pointsArr.reduce((geoPoints, point) => {\n        geoPoints.push(point.x, point.y, point.z);\n        return geoPoints;\n      }, []);\n      let lineGeometry = new _LineGeometry.LineGeometry();\n      lineGeometry.setPositions(lineGeoPoints);\n      let lineMaterial = new _LineMaterial.LineMaterial({\n        transparent: true,\n        color,\n        opacity,\n        linewidth: thickness >= MIN_THICKNESS ? thickness : MIN_THICKNESS\n      });\n      let line = new _Line.Line2(lineGeometry, lineMaterial);\n      line.scale.set(1, 1, 1);\n      return line;\n    }\n\n    getColorAndOpacity(colorProps) {\n      let color = \"rgb(\" + colorProps.red + \", \" + colorProps.green + \", \" + colorProps.blue + \")\";\n      let opacity = colorProps.alpha / 255;\n      return {\n        color,\n        opacity\n      };\n    }\n\n    alignObjectWithVectors(object, normalVector, directionVector) {\n      let newUpVector = new this.THREE.Vector3().crossVectors(normalVector, directionVector);\n      let dotProduct = object.up.dot(newUpVector);\n      let rotationAngle = -Math.acos(dotProduct);\n      object.rotateOnAxis(normalVector, rotationAngle);\n      object.up = newUpVector;\n      object.lookAt(normalVector.add(object.position));\n    }\n\n    makeTestMesh(position, size = 1, color = 0xff0000) {\n      let geo = new this.THREE.BoxBufferGeometry(size, size, size);\n      let mat = new this.THREE.MeshBasicMaterial({\n        color\n      });\n      let mesh = new this.THREE.Mesh(geo, mat);\n      mesh.position.copy(position);\n      return mesh;\n    }\n\n    processUnits(unitsData) {\n      let units = {\n        length: \"\",\n        angle: \"\",\n        mass: \"\",\n        force: \"\",\n        temperature: \"\"\n      };\n\n      switch (unitsData.length) {\n        case 1:\n          units.length = \"mm\";\n          break;\n\n        case 2:\n          units.length = \"cm\";\n          break;\n\n        case 3:\n          units.length = \"m\";\n          break;\n\n        case 4:\n          units.length = \"km\";\n          break;\n\n        default:\n          break;\n      }\n\n      switch (unitsData.angle) {\n        case 1:\n          units.angle = \"deg\";\n          break;\n\n        case 2:\n          units.angle = \"rad\";\n          break;\n\n        default:\n          break;\n      }\n\n      switch (unitsData.mass) {\n        case 1:\n          units.mass = \"g\";\n          break;\n\n        case 2:\n          units.mass = \"kg\";\n          break;\n\n        case 3:\n          units.mass = \"t\";\n          break;\n\n        default:\n          break;\n      }\n\n      switch (unitsData.force) {\n        case 1:\n          units.force = \"N\";\n          break;\n\n        case 2:\n          units.force = \"kN\";\n          break;\n\n        case 3:\n          units.force = \"MN\";\n          break;\n\n        default:\n          break;\n      }\n\n      switch (unitsData.temperature) {\n        case 1:\n          units.temperature = \"degC\";\n          break;\n\n        case 2:\n          units.temperature = \"degF\";\n          break;\n\n        default:\n          break;\n      }\n\n      return units;\n    }\n\n  }\n\n  _exports.Utils = Utils;\n});","define(\"m08-2020/lib/Utils/BooleanOperations\", [\"exports\", \"three\", \"polybooljs\", \"m08-2020/lib/CSGMesh\"], function (_exports, THREE, _polybooljs, _CSGMesh) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.applyCSG = applyCSG;\n  _exports.doCSG = doCSG;\n  _exports.makeCombinedSegments2D = makeCombinedSegments2D;\n  _exports.doSegmentsOperation = doSegmentsOperation;\n  _exports.makePolygonsFromPosAndNegRegions = makePolygonsFromPosAndNegRegions;\n  const CSG = (0, _CSGMesh.CsgFactory)(THREE);\n\n  function applyCSG(positiveObjects, negativeObjects) {\n    let positiveObject = positiveObjects.splice(0, 1)[0];\n    positiveObjects.forEach(object => positiveObject = doCSG(positiveObject, object, \"union\"));\n    negativeObjects.forEach(object => positiveObject = doCSG(positiveObject, object, \"subtract\"));\n    return positiveObject;\n  }\n\n  function doCSG(a, b, op) {\n    let bspA = CSG.fromMesh(a);\n    let bspB = CSG.fromMesh(b);\n    let bspC = bspA[op](bspB);\n    let result = CSG.toMesh(bspC, new THREE.Matrix4());\n    return result;\n  }\n\n  function makePolygonsFromPosAndNegRegions(regions) {\n    let positives = regions.positiveRegions;\n    let negatives = regions.negativeRegions;\n    let segmentsPos = makeCombinedSegments2D(positives, \"selectUnion\");\n    let segmentsNeg = negatives.length > 0 ? makeCombinedSegments2D(negatives, \"selectUnion\") : null;\n    let finalSegments = segmentsNeg ? doSegmentsOperation(segmentsPos, segmentsNeg, \"selectDifference\") : segmentsPos;\n\n    let finalPolygons = _polybooljs.default.polygon(finalSegments);\n\n    return finalPolygons;\n  }\n\n  function makeCombinedSegments2D(regions, operation) {\n    let segments = _polybooljs.default.segments(regions[0]);\n\n    for (let i = 1; i < regions.length; i++) {\n      let tempSegment = _polybooljs.default.segments(regions[i]);\n\n      segments = doSegmentsOperation(segments, tempSegment, operation);\n    }\n\n    return segments;\n  }\n\n  function doSegmentsOperation(segmentOne, segmentTwo, operation) {\n    let combined = _polybooljs.default.combine(segmentOne, segmentTwo);\n\n    return _polybooljs.default[operation](combined);\n  }\n});","define(\"m08-2020/lib/Utils/DimensionalChainIntersectionDetection\", [\"exports\", \"three\", \"m08-2020/lib/Utils\"], function (_exports, THREE, _Utils) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.DimensionalChainIntersectionDetection = void 0;\n  let utils = new _Utils.Utils(THREE);\n\n  class DimensionalChainIntersectionDetection {\n    constructor() {\n      this.meshArr = []; // [ DoubleFace, FrontFace, BackFace ]\n\n      this.chainArr = []; // [ DoubleFace, FrontFace, BackFace ]\n    }\n\n    checkCollision(linePtsArr, objArr) {\n      let isIntersection = false;\n      let raycaster = new THREE.Raycaster();\n      linePtsArr.forEach(([pointOne, pointTwo]) => {\n        let pointsDistance = pointOne.distanceTo(pointTwo);\n        let intersectionsOne = this.getIntersections(raycaster, [pointOne, pointTwo], objArr);\n        let intersectionsTwo = this.getIntersections(raycaster, [pointTwo, pointOne], objArr);\n        if (this.intersectionDetected(pointsDistance, intersectionsOne, intersectionsTwo)) isIntersection = true;\n      });\n      return isIntersection;\n    }\n\n    intersectionDetected(pointsDistance, intersectionsOne, intersectionsTwo) {\n      let [intersectionsOneDouble, intersectionsOneFront, intersectionsOneBack] = intersectionsOne;\n      let [intersectionsTwoDouble, intersectionsTwoFront, intersectionsTwoBack] = intersectionsTwo;\n      let mutualIntersections = this.getMutualIntersections(intersectionsOneDouble, intersectionsTwoDouble);\n      return mutualIntersections.length !== 1 && this.bothPointsOutsideMesh(mutualIntersections, pointsDistance) || this.onePointInsideMeshOneOut(mutualIntersections, intersectionsOneDouble, intersectionsTwoDouble) || this.bothPointsInMesh(intersectionsOneBack, intersectionsTwoBack, intersectionsOneFront, intersectionsTwoFront);\n    }\n\n    bothPointsOutsideMesh(mutualIntersections, pointsDistance) {\n      let intersectionInMiddle = false;\n      mutualIntersections.forEach(intersection => {\n        if (intersection.distance < pointsDistance) intersectionInMiddle = true;\n      });\n      return intersectionInMiddle;\n    }\n\n    onePointInsideMeshOneOut(mutualIntersections, intersectionsOneDouble, intersectionsTwoDouble) {\n      let pointOneInside = this.pointInsideMesh(intersectionsOneDouble);\n      let pointTwoInside = this.pointInsideMesh(intersectionsTwoDouble);\n      return mutualIntersections.length > 0 && (pointOneInside && !pointTwoInside || !pointOneInside && pointTwoInside);\n    }\n\n    bothPointsInMesh(intersectionsOneBack, intersectionsTwoBack, intersectionsOneFront, intersectionsTwoFront) {\n      return intersectionsOneBack.length > 0 && intersectionsTwoBack.length > 0 && intersectionsOneFront.length === 0 && intersectionsTwoFront.length === 0;\n    }\n\n    getIntersections(raycaster, ptsPair, meshArr) {\n      let [pointOne, pointTwo] = ptsPair;\n      let direction = pointTwo.clone().sub(pointOne).normalize();\n      raycaster.set(pointOne, direction);\n      let intersectionsDouble = [];\n      let intersectionsFront = [];\n      let intersectionsBack = [];\n      const DELTA = 1e-4;\n      meshArr.forEach(([meshDoubleFace, meshFrontFace, meshBackFace]) => {\n        intersectionsDouble.push(...raycaster.intersectObject(meshDoubleFace).filter(intersection => intersection.distance > DELTA));\n        intersectionsFront.push(...raycaster.intersectObject(meshFrontFace).filter(intersection => intersection.distance > DELTA));\n        intersectionsBack.push(...raycaster.intersectObject(meshBackFace).filter(intersection => intersection.distance > DELTA));\n      });\n      intersectionsDouble = this.removeDuplicateIntersections(intersectionsDouble);\n      intersectionsFront = this.removeDuplicateIntersections(intersectionsFront);\n      intersectionsBack = this.removeDuplicateIntersections(intersectionsBack);\n      return [intersectionsDouble, intersectionsFront, intersectionsBack];\n    }\n\n    getMutualIntersections(intersectionsOne, intersectionsTwo) {\n      let intersections = intersectionsOne.filter(intersectionOne => {\n        let isMutual = false;\n        let testPoint = intersectionOne.point;\n        intersectionsTwo.forEach(intersectionTwo => {\n          if (utils.checkVectorsEquality(intersectionTwo.point, testPoint)) isMutual = true;\n        });\n        return isMutual;\n      });\n      return intersections;\n    }\n\n    removeDuplicateIntersections(intersections) {\n      let filterArr = [];\n      intersections.forEach(intersection => {\n        let isUnique = true;\n        filterArr.forEach(([key, _]) => {\n          if (utils.vectorsAreEqual(intersection.point, key)) isUnique = false;\n        });\n        if (isUnique) filterArr.push([intersection.point, intersection]);\n      });\n      intersections = filterArr.map(([_, value]) => value);\n      return intersections;\n    }\n\n    intersectionsSharePoints(intersectionsOne, intersectionsTwo) {\n      let intersectionsSharePoints = false;\n\n      for (let intersectionOne of intersectionsOne) {\n        for (let intersectionTwo of intersectionsTwo) {\n          if (utils.vectorsAreEqual(intersectionOne.point, intersectionTwo.point)) intersectionsSharePoints = true;\n        }\n      }\n\n      return intersectionsSharePoints;\n    }\n\n    pointInsideMesh(intersections) {\n      return intersections.length % 2;\n    }\n\n  }\n\n  _exports.DimensionalChainIntersectionDetection = DimensionalChainIntersectionDetection;\n});","define(\"m08-2020/lib/Utils/LineIntersectionDetection\", [\"exports\"], function (_exports) {\n  \"use strict\";\n  /**\n   * https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/\n   * Check if Lines intersect 2D\n   */\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.linesIntersect = linesIntersect;\n  _exports.orientation = orientation;\n  _exports.onSegment = onSegment;\n\n  function onSegment(p, q, r) {\n    // p, q and r points are colinear, q lies on line segment pr\n    return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);\n  }\n\n  function orientation(p, q, r) {\n    /**\n     * 0: Colinear\n     * 1: Clockwise\n     * 2: Counterclockwise\n     */\n    let val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);\n    if (val > 0) return 1;else if (val < 0) return 2;else return 0;\n  }\n\n  function linesIntersect(p1, q1, p2, q2) {\n    /**\n     * p1, q1 -> first line points\n     * p2, q2 -> second line points\n     */\n    // Get orientations\n    let o1 = orientation(p1, q1, p2);\n    let o2 = orientation(p1, q1, q2);\n    let o3 = orientation(p2, q2, p1);\n    let o4 = orientation(p2, q2, q1); // General Case\n\n    if (o1 !== o2 && o3 !== o4) return true; // Special Cases\n    // p1, q1 and p2 are colinear and p2 lies on segment p1q1\n\n    if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and q2 are colinear and q2 lies on segment p1q1\n\n    if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p2, q2 and p1 are colinear and p1 lies on segment p2q2\n\n    if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and q1 are colinear and q1 lies on segment p2q2\n\n    if (o4 === 0 && onSegment(p2, q1, q2)) return true; // no intersection\n\n    return false;\n  }\n});","define(\"m08-2020/lib/Utils/PointInsidePolygonCheck2D\", [\"exports\", \"m08-2020/lib/Utils/LineIntersectionDetection\"], function (_exports, _LineIntersectionDetection) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.pointInsidePolygon2D = pointInsidePolygon2D;\n  _exports.Point2D = void 0;\n\n  class Point2D {\n    constructor(x, y) {\n      this.x = x;\n      this.y = y;\n    }\n\n  }\n\n  _exports.Point2D = Point2D;\n\n  function pointInsidePolygon2D(polygon, point) {\n    const INFINITE_VALUE = Number.MAX_VALUE;\n    const N = polygon.length;\n    if (N < 3) return false;\n    let extremePoint = new Point2D(INFINITE_VALUE, point.y);\n    let count = 0;\n\n    for (let i = 0; i < N - 1; i++) {\n      let j = i + 1;\n\n      if ((0, _LineIntersectionDetection.linesIntersect)(polygon[i], polygon[j], point, extremePoint)) {\n        if ((0, _LineIntersectionDetection.orientation)(polygon[i], point, polygon[j]) === 0) return (0, _LineIntersectionDetection.onSegment)(polygon[i], point, polygon[j]);\n        count++;\n      }\n    }\n\n    return count % 2 === 1;\n  }\n});","define(\"m08-2020/lib/WireframeGenerator\", [\"exports\", \"three\", \"m08-2020/lib/Utils\", \"m08-2020/lib/ThreeExtensions/OutlinesGeometry\", \"m08-2020/lib/Utils/BooleanOperations\"], function (_exports, THREE, _Utils, _OutlinesGeometry, BooleanOperations) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.WireframeGenerator = void 0;\n  const utils = new _Utils.Utils(THREE);\n\n  class WireframeGenerator {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.areaWireframesData = [];\n      this.volumeWireframesData = {\n        opaque: {\n          positives: [],\n          negatives: []\n        },\n        transparent: {\n          positives: [],\n          negatives: []\n        }\n      };\n    }\n\n    applyWireframesArea(object, objectTransparent, lineProps, objectData) {\n      const RENDER_ORDER = -99;\n      let pointPairs = this.getRegularWireframePointPairs(object);\n      pointPairs.forEach(pair => {\n        let wireframe = this.drawObjectLine(pair, lineProps);\n        wireframe.renderOrder = RENDER_ORDER;\n\n        wireframe.onBeforeRender = function (renderer) {\n          renderer.clearDepth();\n        };\n\n        let wireframeClone = wireframe.clone();\n        wireframeClone.isLine = true;\n        if (wireframe.needsZoomControl) wireframeClone.needsZoomControl = true;\n        if (wireframe.pointsStartEnd) wireframeClone.pointsStartEnd = wireframe.pointsStartEnd;\n        object.add(wireframe);\n        if (objectTransparent) objectTransparent.add(wireframeClone);\n      });\n      object.dxfPoints = [{\n        id: objectData.id,\n        pointPairs: pointPairs.map(pair => pair.map(pt => pt.clone())),\n        lineProps\n      }];\n    }\n\n    applyWireframesVolume(object, objectTransparent, lineProps, objectData) {\n      let pointPairs = [];\n      this.mergeVolumeWireframes(\"opaque\");\n      this.mergeVolumeWireframes(\"transparent\");\n      this.createLinesFromWireframeData(\"opaque\", object, lineProps);\n      this.createLinesFromWireframeData(\"transparent\", objectTransparent, lineProps, pointPairs);\n      this.clearWireframeState();\n      object.dxfPoints = [{\n        id: objectData.id,\n        pointPairs,\n        lineProps\n      }];\n    }\n\n    createLinesFromWireframeData(type, object, lineProps, pointPairs = null) {\n      const RENDER_ORDER = -99;\n      const DELTA = 0.0001;\n      this.volumeWireframesData[type].forEach(({\n        linePoints\n      }) => {\n        linePoints.forEach(([pointOne, pointTwo]) => {\n          if (pointOne.distanceTo(pointTwo) > DELTA) {\n            let line = this.drawObjectLine([pointOne, pointTwo], lineProps);\n            line.renderOrder = RENDER_ORDER;\n\n            line.onBeforeRender = function (renderer) {\n              renderer.clearDepth();\n            };\n\n            if (object) object.add(line);\n            if (pointPairs) pointPairs.push([pointOne.clone(), pointTwo.clone()]);\n          }\n        });\n      });\n    } ///\n\n\n    drawObjectLine(pointPair, lineProps) {\n      let firstLine;\n\n      if (canDrawLine(lineProps)) {\n        if (canDrawSolidLine(lineProps)) firstLine = this.drawSolidLine(pointPair, lineProps, true);else if (canDrawDashedLine(lineProps)) firstLine = this.drawDashedLine(pointPair, lineProps);else firstLine = utils.drawConnectedLines(pointPair, lineProps);\n      } else firstLine = new THREE.Mesh();\n\n      firstLine.isLine = true;\n      firstLine.pointsStartEnd = {\n        startPoint: pointPair[0],\n        endPoint: pointPair[1]\n      }; // Helper functions -->\n\n      function canDrawLine(lineProps) {\n        return lineProps.thickness && lineProps.color.alpha && (lineProps.type || lineProps.type === undefined);\n      }\n\n      function canDrawSolidLine(lineProps) {\n        return lineProps.type === 1 || lineProps.type === undefined || lineProps.factor === 0 && lineProps.type !== null && lineProps.type !== 0;\n      }\n\n      function canDrawDashedLine(lineProps) {\n        return lineProps.type === 2;\n      } // <-- Helper functions\n\n\n      return firstLine;\n    }\n\n    drawSolidLine(points, lineProps) {\n      let lineMesh;\n\n      if (points[0].distanceTo(points[1]) > 0) {\n        lineMesh = utils.drawLine(points[0], points[1], lineProps, true);\n      } else {\n        lineMesh = new THREE.Mesh();\n      }\n\n      lineMesh.needsZoomControl = true;\n      return lineMesh;\n    }\n\n    drawDashedLine(pointPair, lineProps) {\n      let localPoints = pointPair.map(pt => pt.clone().sub(pointPair[0]));\n      let factor = lineProps.factor;\n      let q = new THREE.Quaternion().setFromUnitVectors(localPoints[1].clone().normalize(), new THREE.Vector3(0, 0, 1));\n      localPoints[1].applyQuaternion(q);\n      let lineSegments = this.getDashedLineSegments(localPoints[0], localPoints[1], factor);\n      let lineMesh = this.drawDashedLineFromSegments(lineSegments, lineProps);\n      lineMesh.position.add(pointPair[0]);\n      lineMesh.lookAt(pointPair[1]);\n      lineMesh.needsZoomControl = true;\n      return lineMesh;\n    }\n\n    getDashedLineSegments(pointOne, pointTwo, factor) {\n      let pointPairs = [];\n      let newSegment = true;\n      let direction = new THREE.Vector3().subVectors(pointTwo, pointOne).normalize();\n      let distance = pointOne.distanceTo(pointTwo);\n      let segmentSize = factor;\n\n      if (distance > factor) {\n        while (distance > segmentSize) {\n          let newPoint = new THREE.Vector3().copy(pointOne).add(direction.clone().multiplyScalar(segmentSize));\n          if (newSegment) pointPairs.push([pointOne, newPoint]);\n          pointOne = newPoint;\n          distance -= segmentSize;\n          newSegment = !newSegment;\n        }\n      } else pointPairs.push([pointOne, pointTwo]);\n\n      return pointPairs;\n    }\n\n    drawDashedLineFromSegments(lineSegments, lineProps) {\n      let lineMeshArray = [];\n      lineSegments.forEach(pair => {\n        if (pair[0].distanceTo(pair[1]) > 0) {\n          let lineMesh = utils.drawLine(pair[0], pair[1], lineProps);\n          lineMeshArray.push(lineMesh);\n        }\n      });\n      let firstLine = lineMeshArray.splice(0, 1)[0];\n      let lineMaterial = firstLine.material;\n      firstLine.updateMatrixWorld();\n      firstLine.geometry.applyMatrix4(firstLine.matrixWorld);\n\n      for (let i = 0; i < lineMeshArray.length; i++) {\n        lineMeshArray[i].updateMatrixWorld();\n        lineMeshArray[i].geometry.applyMatrix4(lineMeshArray[i].matrixWorld);\n        firstLine.geometry.merge(lineMeshArray[i].geometry);\n      }\n\n      firstLine = new THREE.Mesh(firstLine.geometry, lineMaterial);\n      return firstLine;\n    } ///\n\n\n    mergeVolumeWireframes(type) {\n      const DELTA = 0.0001;\n      let raycaster = new THREE.Raycaster();\n      let positives = this.mergeSameTypeWireframe(raycaster, this.volumeWireframesData[type], \"positives\");\n      let negatives = this.mergeSameTypeWireframe(raycaster, this.volumeWireframesData[type], \"negatives\");\n      if (positives.mesh) positives.mesh.material.side = THREE.DoubleSide;\n      if (negatives.mesh) negatives.mesh.material.side = THREE.DoubleSide;\n      this.volumeWireframesData[type] = [positives, negatives];\n\n      for (let objectData of this.volumeWireframesData[type]) {\n        let id = objectData.id;\n        let mesh = objectData.mesh;\n        let objectType = objectData.objectType;\n        this.volumeWireframesData[type].filter(obj => id !== obj.id).map(obj => obj.mesh).forEach(objMesh => {\n          let newPoints = [];\n          objectData.linePoints.forEach(([pointOne, pointTwo]) => {\n            pointOne.applyMatrix4(mesh.matrix);\n            pointTwo.applyMatrix4(mesh.matrix);\n            let firstPointIntersection = this.pointInsideMesh(raycaster, pointOne, pointTwo, objMesh);\n            let secondPointIntersection = this.pointInsideMesh(raycaster, pointTwo, pointOne, objMesh);\n            let firstPointData = {\n              point: pointOne,\n              intersection: firstPointIntersection\n            };\n            let secondPointData = {\n              point: pointTwo,\n              intersection: secondPointIntersection\n            };\n            let operation = objectType === 1 ? \"AddPoints\" : \"SubtractPoints\";\n            let correctedPointPairs = this.getCorrectedLinePoints(firstPointData, secondPointData, operation);\n            correctedPointPairs.forEach(pair => {\n              if (pair[0].distanceTo(pair[1]) > DELTA) {\n                newPoints.push([pair[0], pair[1]]);\n              }\n            });\n          });\n          objectData.linePoints = newPoints;\n        });\n      }\n    }\n\n    mergeSameTypeWireframe(raycaster, volumeWireframes, type) {\n      let mergedWireframes = volumeWireframes[type];\n\n      for (let i = 0; i < mergedWireframes.length; i++) {\n        let objectData = mergedWireframes[i];\n        let id = objectData.id;\n        let mesh = objectData.mesh;\n        mergedWireframes.filter(obj => id !== obj.id).map(obj => obj.mesh).forEach(objMesh => {\n          let newPoints = [];\n          objectData.linePoints.forEach(([pointOne, pointTwo]) => {\n            pointOne.applyMatrix4(mesh.matrix);\n            pointTwo.applyMatrix4(mesh.matrix);\n            let firstPointIntersection = this.pointInsideMesh(raycaster, pointOne, pointTwo, objMesh);\n            let secondPointIntersection = this.pointInsideMesh(raycaster, pointTwo, pointOne, objMesh);\n            let firstPointData = {\n              point: pointOne,\n              intersection: firstPointIntersection\n            };\n            let secondPointData = {\n              point: pointTwo,\n              intersection: secondPointIntersection\n            };\n            let correctedPointPairs = this.getCorrectedLinePoints(firstPointData, secondPointData, \"AddPoints\");\n            correctedPointPairs.forEach(pair => {\n              if (pair[0].distanceTo(pair[1]) > 0.0001) {\n                newPoints.push([pair[0], pair[1]]);\n              }\n            });\n          });\n          objectData.linePoints = newPoints;\n        });\n      }\n\n      mergedWireframes = mergedWireframes.reduce((allPos, currentPos) => {\n        allPos.id = currentPos.id;\n        allPos.objectType = currentPos.objectType;\n        allPos.linePoints.push(...currentPos.linePoints);\n        allPos.mesh = allPos.mesh ? BooleanOperations.doCSG(allPos.mesh, currentPos.mesh, \"union\") : currentPos.mesh;\n        return allPos;\n      }, {\n        linePoints: []\n      });\n      return mergedWireframes;\n    }\n\n    getCorrectedLinePoints(firstPtIntersect, secondPtIntersect, operationType) {\n      let pointOne = firstPtIntersect.point;\n      let firstPointIntersection = firstPtIntersect.intersection;\n      let pointTwo = secondPtIntersect.point;\n      let secondPointIntersection = secondPtIntersect.intersection;\n      let linePairs = [];\n\n      if (operationType === \"AddPoints\") {\n        if (!firstPointIntersection.isInMesh && !secondPointIntersection.isInMesh) {\n          if (firstPointIntersection.intersectionPoint && secondPointIntersection.intersectionPoint) {\n            let lenPointToPoint = pointOne.distanceTo(pointTwo);\n            let lenPointOneToIntersect = pointOne.distanceTo(firstPointIntersection.intersectionPoint);\n            let lenPointTwoToIntersect = pointTwo.distanceTo(secondPointIntersection.intersectionPoint);\n\n            if (lenPointToPoint > lenPointOneToIntersect && lenPointToPoint > lenPointTwoToIntersect) {\n              linePairs.push([pointOne, firstPointIntersection.intersectionPoint]);\n              linePairs.push([pointTwo, secondPointIntersection.intersectionPoint]);\n            } else {\n              linePairs.push([pointOne, pointTwo]);\n            }\n          } else {\n            linePairs.push([pointOne, pointTwo]);\n          }\n        } else if (!firstPointIntersection.isInMesh && secondPointIntersection.isInMesh) {\n          if (firstPointIntersection.intersectionPoint) linePairs.push([pointOne, secondPointIntersection.intersectionPoint]);\n        } else if (firstPointIntersection.isInMesh && !secondPointIntersection.isInMesh) {\n          if (secondPointIntersection.intersectionPoint) linePairs.push([pointTwo, firstPointIntersection.intersectionPoint]);\n        }\n      } else if (operationType === \"SubtractPoints\") {\n        if (firstPointIntersection.isInMesh && secondPointIntersection.isInMesh) {\n          linePairs.push([pointOne, pointTwo]);\n        } // else if ( !firstPointIntersection.isInMesh && secondPointIntersection.isInMesh && firstPointIntersection.intersectionPoint )\n        // {\n        //   linePairs.push([ pointTwo, secondPointIntersection.intersectionPoint ]);\n        // }\n        // else if ( firstPointIntersection.isInMesh && !secondPointIntersection.isInMesh && secondPointIntersection.intersectionPoint )\n        // {\n        //   linePairs.push([ pointOne, firstPointIntersection.intersectionPoint ]);\n        // }\n\n      }\n\n      return linePairs;\n    }\n\n    pointInsideMesh(raycaster, pointOne, pointTwo, object) {\n      if (!object) {\n        return {\n          isInMesh: false,\n          intersectionPoint: null\n        };\n      }\n\n      let direction = pointTwo.clone().sub(pointOne).normalize();\n      raycaster.set(pointOne, direction);\n      let intersects = raycaster.intersectObject(object);\n\n      for (let i = 0; i < intersects.length; i++) {\n        for (let j = 0; j < intersects.length; j++) {\n          if (i != j && Math.abs(intersects[i].distance - intersects[j].distance) < 0.1) {\n            intersects[i].markedToDelete = true && !intersects[j].markedToDelete;\n          }\n        }\n      }\n\n      intersects = intersects.filter(intersect => !intersect.markedToDelete);\n      let intersectionData = {\n        isInMesh: intersects.length % 2 ? true : false,\n        intersectionPoint: intersects[0] ? intersects[0].point : null\n      };\n      return intersectionData;\n    }\n\n    getRegularWireframePointPairs(object, threshold = Math.PI / 6) {\n      let edgesGeo = new _OutlinesGeometry.OutlinesGeometry(object.geometry);\n      let pointPairs = [];\n      this.getWireframeLinePairs(edgesGeo, threshold).forEach(([_, pairs]) => pairs.forEach(pair => pointPairs.push(pair)));\n      return pointPairs;\n    }\n\n    getWireframeLinePairs(edgesGeo, threshold = Math.PI / 6) {\n      const DELTA = 0.0001;\n      let facesDict = this.getFacesDict(edgesGeo.faces);\n      let linePairs = [];\n\n      for (let [edgeIndices, facePair] of Object.entries(facesDict)) {\n        if (facePair.length === 2) {\n          let faceOne = facePair[0];\n          let faceTwo = facePair[1];\n\n          if (faceOne.normal.angleTo(faceTwo.normal) > threshold) {\n            let verticesIdx = edgeIndices.split(\",\").map(val => parseInt(val));\n            let vectorOne = edgesGeo.vertices[verticesIdx[0]];\n            let vectorTwo = edgesGeo.vertices[verticesIdx[1]];\n            let direction = new THREE.Vector3().subVectors(vectorTwo, vectorOne).normalize();\n            let needToAdd = false;\n\n            for (let k = 0; k < linePairs.length; k++) {\n              needToAdd = false;\n              let vectorData = linePairs[k];\n              let dir = vectorData[0];\n              let vectorsArr = vectorData[1];\n              let dirDot = dir.dot(direction);\n\n              if (dirDot > 1 - DELTA) {\n                vectorsArr.push([vectorOne, vectorTwo]);\n                k = linePairs.length;\n              } else if (dirDot < -1 + DELTA) {\n                vectorsArr.push([vectorTwo, vectorOne]);\n                k = linePairs.length;\n              } else needToAdd = true;\n            }\n\n            if (linePairs.length === 0) needToAdd = true;\n            if (needToAdd) linePairs.push([direction, [[vectorOne, vectorTwo]]]);\n          }\n        } else {\n          let verticesIdx = edgeIndices.split(\",\").map(val => parseInt(val));\n          let vectorOne = edgesGeo.vertices[verticesIdx[0]];\n          let vectorTwo = edgesGeo.vertices[verticesIdx[1]];\n          let direction = new THREE.Vector3().subVectors(vectorTwo, vectorOne).normalize();\n          let needToAdd = false;\n\n          for (let k = 0; k < linePairs.length; k++) {\n            needToAdd = false;\n            let vectorData = linePairs[k];\n            let dir = vectorData[0];\n            let vectorsArr = vectorData[1];\n            let dirDot = dir.dot(direction);\n\n            if (dirDot > 1 - DELTA) {\n              vectorsArr.push([vectorOne, vectorTwo]);\n              k = linePairs.length;\n            } else if (dirDot < -1 + DELTA) {\n              vectorsArr.push([vectorTwo, vectorOne]);\n              k = linePairs.length;\n            } else needToAdd = true;\n          }\n\n          if (linePairs.length === 0) needToAdd = true;\n          if (needToAdd) linePairs.push([direction, [[vectorOne, vectorTwo]]]);\n        }\n      }\n\n      this.mergeLinePairsSameDirection(linePairs);\n      return linePairs;\n    }\n\n    getFacesDict(faces) {\n      let facesDict = {};\n\n      for (let face of faces) {\n        if (face.splitted) continue;\n        let edgeOne = `${face.a},${face.b}`;\n        let edgeTwo = `${face.b},${face.c}`;\n        let edgeThree = `${face.c},${face.a}`;\n        let edgeOneReversed = `${face.b},${face.a}`;\n        let edgeTwoReversed = `${face.c},${face.b}`;\n        let edgeThreeReversed = `${face.a},${face.c}`;\n        if (edgeOneReversed in facesDict) facesDict[edgeOneReversed].push(face);else if (edgeOne in facesDict) facesDict[edgeOne].push(face);else {\n          facesDict[edgeOne] = [];\n          facesDict[edgeOne].push(face);\n        }\n        if (edgeTwoReversed in facesDict) facesDict[edgeTwoReversed].push(face);else if (edgeTwo in facesDict) facesDict[edgeTwo].push(face);else {\n          facesDict[edgeTwo] = [];\n          facesDict[edgeTwo].push(face);\n        }\n        if (edgeThreeReversed in facesDict) facesDict[edgeThreeReversed].push(face);else if (edgeThree in facesDict) facesDict[edgeThree].push(face);else {\n          facesDict[edgeThree] = [];\n          facesDict[edgeThree].push(face);\n        }\n      }\n\n      return facesDict;\n    }\n\n    mergeLinePairsSameDirection(linePairs) {\n      linePairs.forEach(arrData => this.makeLinePairsUnique(arrData));\n      linePairs.forEach(([direction, pairs]) => utils.mergeLinePoints(pairs, direction));\n    }\n\n    makeLinePairsUnique(arrData) {\n      // [ 0: Direction, 1: Pairs array ]\n      let vectorPairsArr = arrData[1];\n      let uniquePairs = [];\n      vectorPairsArr.forEach(pair => {\n        let isUnique = true;\n        uniquePairs.forEach(uniquePair => {\n          if (pair[0].equals(uniquePair[0]) && pair[1].equals(uniquePair[1])) isUnique = false;\n        });\n        if (isUnique) uniquePairs.push(pair);\n      });\n      arrData[1] = uniquePairs;\n    }\n\n    getVolumeWireframeData(mesh, linePairsForOpaque, linePairsForTransparent, objectType) {\n      let intersectionGeo = mesh.geometry.clone(); // For checking if line intersects faces\n\n      intersectionGeo.applyMatrix4(mesh.matrix);\n      let intersectionMesh = new THREE.Mesh(intersectionGeo, new THREE.MeshBasicMaterial({\n        side: THREE.DoubleSide\n      }));\n\n      if (objectType === 1) {\n        this.volumeWireframesData.opaque.positives.push({\n          id: intersectionMesh.uuid,\n          linePoints: linePairsForOpaque,\n          mesh: intersectionMesh,\n          objectType\n        });\n        this.volumeWireframesData.transparent.positives.push({\n          id: intersectionMesh.uuid,\n          linePoints: linePairsForTransparent,\n          mesh: intersectionMesh,\n          objectType\n        });\n      } else if (objectType === 2) {\n        this.volumeWireframesData.opaque.negatives.push({\n          id: intersectionMesh.uuid,\n          linePoints: linePairsForOpaque,\n          mesh: intersectionMesh,\n          objectType\n        });\n        this.volumeWireframesData.transparent.negatives.push({\n          id: intersectionMesh.uuid,\n          linePoints: linePairsForTransparent,\n          mesh: intersectionMesh,\n          objectType\n        });\n      }\n    }\n\n    clearWireframeState() {\n      this.areaWireframesData = [];\n      this.volumeWireframesData = {\n        opaque: {\n          positives: [],\n          negatives: []\n        },\n        transparent: {\n          positives: [],\n          negatives: []\n        }\n      };\n    }\n\n  }\n\n  _exports.WireframeGenerator = WireframeGenerator;\n});","define(\"m08-2020/lib/ZoomController\", [\"exports\", \"three\"], function (_exports, THREE) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.ZoomController = void 0;\n\n  class ZoomController {\n    constructor(GraphicsThree3D) {\n      this.GraphicsThree3D = GraphicsThree3D;\n      this.controls = GraphicsThree3D.controls;\n      this.camera = GraphicsThree3D.camera;\n      this.drawingObjectWireframesSolid = []; ///\n\n      this.controls.addEventListener(\"change\", this.zoomDrawingObjectSolidLines()); ///\n    }\n\n    zoomDrawingObjectSolidLines() {\n      return () => {\n        let startingRotation = new THREE.Euler(),\n            startingPosition = new THREE.Vector3();\n        let scaleFactor = 1 / this.camera.zoom;\n        this.drawingObjectWireframesSolid.forEach(lineData => {\n          if (this.camera.zoom < 1) {\n            startingRotation.copy(lineData.line.rotation);\n            startingPosition.copy(lineData.line.position);\n            lineData.line.position.sub(lineData.line.position);\n            lineData.line.setRotationFromEuler(lineData.eulerOne);\n            lineData.line.scale.set(scaleFactor, scaleFactor, 1);\n            lineData.line.setRotationFromEuler(startingRotation);\n            lineData.line.position.add(startingPosition);\n          }\n        });\n      };\n    }\n\n    getDrawingObjectWireframes(object) {\n      const Z_AXIS = new THREE.Vector3(0, 0, 1);\n      object.children.forEach(child => {\n        // TODO: Add support for buffergeometries\n        if (child.isLine && child.needsZoomControl) {\n          let ptOne = child.pointsStartEnd.startPoint;\n          let ptTwo = child.pointsStartEnd.endPoint;\n          let lineDirection = new THREE.Vector3().copy(ptTwo).sub(ptOne).normalize();\n          let quaternion = new THREE.Quaternion().setFromUnitVectors(lineDirection, Z_AXIS);\n          let quaternionConjugate = new THREE.Quaternion().setFromUnitVectors(Z_AXIS, lineDirection);\n          let eulerOne = new THREE.Euler().setFromQuaternion(quaternion);\n          let eulerTwo = new THREE.Euler().setFromQuaternion(quaternionConjugate);\n          this.drawingObjectWireframesSolid.push({\n            line: child,\n            eulerOne,\n            eulerTwo\n          });\n        }\n      });\n    }\n\n    drawingObjectWireframes() {\n      this.drawingObjectWireframesSolid = [];\n    }\n\n  }\n\n  _exports.ZoomController = ZoomController;\n});","define(\"m08-2020/lib/dxf_colors\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.COLOR_LOOKUP = void 0;\n  const COLOR_LOOKUP = [[0, 0, 0], [255, 0, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255], [255, 0, 255], [255, 255, 255], [128, 128, 128], [192, 192, 192], [255, 0, 0], [255, 127, 127], [204, 0, 0], [204, 102, 102], [153, 0, 0], [153, 76, 76], [127, 0, 0], [127, 63, 63], [76, 0, 0], [76, 38, 38], [255, 63, 0], [255, 159, 127], [204, 51, 0], [204, 127, 102], [153, 38, 0], [153, 95, 76], [127, 31, 0], [127, 79, 63], [76, 19, 0], [76, 47, 38], [255, 127, 0], [255, 191, 127], [204, 102, 0], [204, 153, 102], [153, 76, 0], [153, 114, 76], [127, 63, 0], [127, 95, 63], [76, 38, 0], [76, 57, 38], [255, 191, 0], [255, 223, 127], [204, 153, 0], [204, 178, 102], [153, 114, 0], [153, 133, 76], [127, 95, 0], [127, 111, 63], [76, 57, 0], [76, 66, 38], [255, 255, 0], [255, 255, 127], [204, 204, 0], [204, 204, 102], [153, 153, 0], [153, 153, 76], [127, 127, 0], [127, 127, 63], [76, 76, 0], [76, 76, 38], [191, 255, 0], [223, 255, 127], [153, 204, 0], [178, 204, 102], [114, 153, 0], [133, 153, 76], [95, 127, 0], [111, 127, 63], [57, 76, 0], [66, 76, 38], [127, 255, 0], [191, 255, 127], [102, 204, 0], [153, 204, 102], [76, 153, 0], [114, 153, 76], [63, 127, 0], [95, 127, 63], [38, 76, 0], [57, 76, 38], [63, 255, 0], [159, 255, 127], [51, 204, 0], [127, 204, 102], [38, 153, 0], [95, 153, 76], [31, 127, 0], [79, 127, 63], [19, 76, 0], [47, 76, 38], [0, 255, 0], [127, 255, 127], [0, 204, 0], [102, 204, 102], [0, 153, 0], [76, 153, 76], [0, 127, 0], [63, 127, 63], [0, 76, 0], [38, 76, 38], [0, 255, 63], [127, 255, 159], [0, 204, 51], [102, 204, 127], [0, 153, 38], [76, 153, 95], [0, 127, 31], [63, 127, 79], [0, 76, 19], [38, 76, 47], [0, 255, 127], [127, 255, 191], [0, 204, 102], [102, 204, 153], [0, 153, 76], [76, 153, 114], [0, 127, 63], [63, 127, 95], [0, 76, 38], [38, 76, 57], [0, 255, 191], [127, 255, 223], [0, 204, 153], [102, 204, 178], [0, 153, 114], [76, 153, 133], [0, 127, 95], [63, 127, 111], [0, 76, 57], [38, 76, 66], [0, 255, 255], [127, 255, 255], [0, 204, 204], [102, 204, 204], [0, 153, 153], [76, 153, 153], [0, 127, 127], [63, 127, 127], [0, 76, 76], [38, 76, 76], [0, 191, 255], [127, 223, 255], [0, 153, 204], [102, 178, 204], [0, 114, 153], [76, 133, 153], [0, 95, 127], [63, 111, 127], [0, 57, 76], [38, 66, 76], [0, 127, 255], [127, 191, 255], [0, 102, 204], [102, 153, 204], [0, 76, 153], [76, 114, 153], [0, 63, 127], [63, 95, 127], [0, 38, 76], [38, 57, 76], [0, 63, 255], [127, 159, 255], [0, 51, 204], [102, 127, 204], [0, 38, 153], [76, 95, 153], [0, 31, 127], [63, 79, 127], [0, 19, 76], [38, 47, 76], [0, 0, 255], [127, 127, 255], [0, 0, 204], [102, 102, 204], [0, 0, 153], [76, 76, 153], [0, 0, 127], [63, 63, 127], [0, 0, 76], [38, 38, 76], [63, 0, 255], [159, 127, 255], [51, 0, 204], [127, 102, 204], [38, 0, 153], [95, 76, 153], [31, 0, 127], [79, 63, 127], [19, 0, 76], [47, 38, 76], [127, 0, 255], [191, 127, 255], [102, 0, 204], [153, 102, 204], [76, 0, 153], [114, 76, 153], [63, 0, 127], [95, 63, 127], [38, 0, 76], [57, 38, 76], [191, 0, 255], [223, 127, 255], [153, 0, 204], [178, 102, 204], [114, 0, 153], [133, 76, 153], [95, 0, 127], [111, 63, 127], [57, 0, 76], [66, 38, 76], [255, 0, 255], [255, 127, 255], [204, 0, 204], [204, 102, 204], [153, 0, 153], [153, 76, 153], [127, 0, 127], [127, 63, 127], [76, 0, 76], [76, 38, 76], [255, 0, 191], [255, 127, 223], [204, 0, 153], [204, 102, 178], [153, 0, 114], [153, 76, 133], [127, 0, 95], [127, 63, 111], [76, 0, 57], [76, 38, 66], [255, 0, 127], [255, 127, 191], [204, 0, 102], [204, 102, 153], [153, 0, 76], [153, 76, 114], [127, 0, 63], [127, 63, 95], [76, 0, 38], [76, 38, 57], [255, 0, 63], [255, 127, 159], [204, 0, 51], [204, 102, 127], [153, 0, 38], [153, 76, 95], [127, 0, 31], [127, 63, 79], [76, 0, 19], [76, 38, 47], [51, 51, 51], [91, 91, 91], [132, 132, 132], [173, 173, 173], [214, 214, 214], [255, 255, 255]];\n  _exports.COLOR_LOOKUP = COLOR_LOOKUP;\n});","define(\"m08-2020/mixins/model-validator\", [\"exports\", \"ember-model-validator/mixins/model-validator\"], function (_exports, _modelValidator) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = _modelValidator.default;\n  _exports.default = _default;\n});","define(\"m08-2020/mixins/object-validator\", [\"exports\", \"ember-model-validator/mixins/object-validator\"], function (_exports, _objectValidator) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = _objectValidator.default;\n  _exports.default = _default;\n});","define(\"m08-2020/models/application\", [\"exports\", \"@ember-data/model\"], function (_exports, _model) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  // var lower = 0;\n  // var upper = 100000000;\n  // var calcId = Math.floor(Math.random()*(upper-lower))+lower;\n  var application = _model.default.extend({\n    Calculation_ID: (0, _model.attr)('string'),\n    firm: (0, _model.attr)('string'),\n    //firm\n    spracheinput: (0, _model.attr)('string'),\n    //spracheinput\n    spracheoutput: (0, _model.attr)('string'),\n    //spracheoutput\n    katalog: (0, _model.attr)('string'),\n    //katalog\n    timberCode: (0, _model.attr)('string'),\n    //timberCode\n    timberNA: (0, _model.attr)('string'),\n    //timberNA\n    loadsCode: (0, _model.attr)('string'),\n    //loadsCode\n    loadsNA: (0, _model.attr)('string'),\n    //loadsNA\n    initialized: (0, _model.attr)('boolean'),\n    selectedScrew: (0, _model.attr)('string'),\n    treeLoaded: (0, _model.attr)('boolean'),\n    kennungland: (0, _model.attr)('string'),\n    userID: (0, _model.attr)('string'),\n    userName: (0, _model.attr)('string'),\n    pdfErstellt: (0, _model.attr)('boolean')\n  });\n\n  var _default = application;\n  _exports.default = _default;\n});","define(\"m08-2020/models/position\", [\"exports\", \"@ember-data/model\"], function (_exports, _model) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  var _default = _model.default.extend({\n    x: (0, _model.attr)('number'),\n    y: (0, _model.attr)('number'),\n    z: (0, _model.attr)('number')\n  });\n\n  _exports.default = _default;\n});","define(\"m08-2020/models/rotation\", [\"exports\", \"@ember-data/model\"], function (_exports, _model) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  var _default = _model.default.extend({\n    x: (0, _model.attr)('number'),\n    y: (0, _model.attr)('number'),\n    z: (0, _model.attr)('number'),\n    winkel: (0, _model.attr)('number') // rotation: belongsTo('bauteil', {async: true})\n\n  });\n\n  _exports.default = _default;\n});","define(\"m08-2020/router\", [\"exports\", \"m08-2020/config/environment\"], function (_exports, _environment) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n  class Router extends Ember.Router {\n    constructor(...args) {\n      super(...args);\n\n      _defineProperty(this, \"location\", _environment.default.locationType);\n\n      _defineProperty(this, \"rootURL\", _environment.default.rootURL);\n    }\n\n  }\n\n  _exports.default = Router;\n  Router.map(function () {\n    this.route('projektdaten');\n  });\n});","define(\"m08-2020/routes/application\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  var _default = Ember.Route.extend({\n    intl: Ember.inject.service(),\n\n    beforeModel() {\n      this.intl.setLocale(['de']);\n    },\n\n    model: function () {\n      var self = this;\n      return Ember.RSVP.hash({\n        application: self.store.findAll('application')\n      });\n    },\n\n    setupController(controller, model) {\n      this._super(controller, model);\n\n      setTimeout(function () {// scene.set3DSceneSize(); // ./vendor/scenesizemanagement/scenesizemanagement.js\n      }, 400);\n      $(window).resize(function () {// scene.set3DSceneSize(); // ./vendor/scenesizemanagement/scenesizemanagement.js\n      });\n    }\n\n  });\n\n  _exports.default = _default;\n});","define(\"m08-2020/serializers/-default\", [\"exports\", \"@ember-data/serializer/json\"], function (_exports, _json) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _json.default;\n    }\n  });\n});","define(\"m08-2020/serializers/-json-api\", [\"exports\", \"@ember-data/serializer/json-api\"], function (_exports, _jsonApi) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _jsonApi.default;\n    }\n  });\n});","define(\"m08-2020/serializers/-rest\", [\"exports\", \"@ember-data/serializer/rest\"], function (_exports, _rest) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _rest.default;\n    }\n  });\n});","define(\"m08-2020/services/file-queue\", [\"exports\", \"ember-file-upload/services/file-queue\"], function (_exports, _fileQueue) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _fileQueue.default;\n    }\n  });\n});","define(\"m08-2020/services/intl\", [\"exports\", \"ember-intl/services/intl\"], function (_exports, _intl) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _intl.default;\n    }\n  });\n});","define(\"m08-2020/services/store\", [\"exports\", \"ember-data/store\"], function (_exports, _store) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _store.default;\n    }\n  });\n});","define(\"m08-2020/templates/application\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  var _default = Ember.HTMLBars.template({\n    \"id\": \"PkKBJe9z\",\n    \"block\": \"{\\\"symbols\\\":[],\\\"statements\\\":[[0,\\\"  \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"container\\\"],[8],[0,\\\"\\\\n\\\\n    \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"tlbbtn\\\"],[8],[0,\\\"\\\\n      \\\"],[7,\\\"button\\\",false],[12,\\\"class\\\",\\\"btn btn-default btn-xs\\\"],[12,\\\"type\\\",\\\"button\\\"],[3,\\\"on\\\",[\\\"click\\\",[28,\\\"fn\\\",[[23,0,[\\\"loadAction\\\"]]],null]]],[8],[0,\\\"\\\\n        \\\"],[7,\\\"img\\\",true],[10,\\\"src\\\",\\\"assets/images/folder_page.png\\\"],[10,\\\"alt\\\",\\\"\\\"],[10,\\\"role\\\",\\\"presentation\\\"],[8],[9],[0,\\\"\\\\n      \\\"],[9],[0,\\\"\\\\n      \\\"],[7,\\\"input\\\",false],[12,\\\"id\\\",\\\"file-input\\\"],[12,\\\"name\\\",\\\"name\\\"],[12,\\\"type\\\",\\\"file\\\"],[3,\\\"on\\\",[\\\"change\\\",[28,\\\"fn\\\",[[23,0,[\\\"openFileAction\\\"]]],null]]],[8],[9],[0,\\\"\\\\n    \\\"],[9],[0,\\\"\\\\n\\\\n    \\\"],[7,\\\"div\\\",true],[8],[0,\\\"\\\\n      \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"x3dsteuerelemente\\\"],[8],[0,\\\"\\\\n        \\\"],[7,\\\"button\\\",false],[12,\\\"onclick\\\",\\\"setCameraBinding('viewpointDefault')\\\"],[12,\\\"type\\\",\\\"button\\\"],[3,\\\"on\\\",[\\\"click\\\",[28,\\\"fn\\\",[[23,0,[\\\"ChangePosition0\\\"]],\\\"viewpointDefault\\\"],null]]],[8],[0,\\\"\\\\n          \\\"],[7,\\\"img\\\",true],[10,\\\"src\\\",\\\"assets/images/viewdefault.png\\\"],[10,\\\"alt\\\",\\\"\\\"],[10,\\\"role\\\",\\\"presentation\\\"],[8],[9],[0,\\\"\\\\n        \\\"],[9],[0,\\\"\\\\n        \\\"],[7,\\\"button\\\",false],[12,\\\"onclick\\\",\\\"setCameraBinding('viewpointLinks')\\\"],[12,\\\"type\\\",\\\"button\\\"],[3,\\\"on\\\",[\\\"click\\\",[28,\\\"fn\\\",[[23,0,[\\\"ChangePosition1\\\"]]],null]]],[8],[0,\\\"\\\\n          \\\"],[7,\\\"img\\\",true],[10,\\\"src\\\",\\\"assets/images/viewleft.png\\\"],[10,\\\"alt\\\",\\\"\\\"],[10,\\\"role\\\",\\\"presentation\\\"],[8],[9],[0,\\\"\\\\n        \\\"],[9],[0,\\\"\\\\n        \\\"],[7,\\\"button\\\",false],[12,\\\"onclick\\\",\\\"setCameraBinding('viewpointOben')\\\"],[12,\\\"type\\\",\\\"button\\\"],[3,\\\"on\\\",[\\\"click\\\",[28,\\\"fn\\\",[[23,0,[\\\"ChangePosition2\\\"]]],null]]],[8],[0,\\\"\\\\n          \\\"],[7,\\\"img\\\",true],[10,\\\"src\\\",\\\"assets/images/viewtop.png\\\"],[10,\\\"alt\\\",\\\"\\\"],[10,\\\"role\\\",\\\"presentation\\\"],[8],[9],[0,\\\"\\\\n        \\\"],[9],[0,\\\"\\\\n        \\\"],[7,\\\"button\\\",false],[12,\\\"onclick\\\",\\\"setCameraBinding('viewpointFront')\\\"],[12,\\\"type\\\",\\\"button\\\"],[3,\\\"on\\\",[\\\"click\\\",[28,\\\"fn\\\",[[23,0,[\\\"ChangePosition3\\\"]]],null]]],[8],[0,\\\"\\\\n          \\\"],[7,\\\"img\\\",true],[10,\\\"src\\\",\\\"assets/images/viewfront.png\\\"],[10,\\\"alt\\\",\\\"\\\"],[10,\\\"role\\\",\\\"presentation\\\"],[8],[9],[0,\\\"\\\\n        \\\"],[9],[0,\\\"\\\\n        \\\"],[7,\\\"button\\\",false],[12,\\\"type\\\",\\\"button\\\"],[3,\\\"on\\\",[\\\"click\\\",[28,\\\"fn\\\",[[23,0,[\\\"ToggleWireframe\\\"]]],null]]],[8],[0,\\\"\\\\n          \\\"],[7,\\\"img\\\",true],[10,\\\"src\\\",\\\"assets/images/gitter.png\\\"],[10,\\\"alt\\\",\\\"\\\"],[10,\\\"role\\\",\\\"presentation\\\"],[8],[9],[0,\\\"\\\\n        \\\"],[9],[0,\\\"\\\\n        \\\"],[7,\\\"button\\\",false],[12,\\\"type\\\",\\\"button\\\"],[3,\\\"on\\\",[\\\"click\\\",[28,\\\"fn\\\",[[23,0,[\\\"loadDrawingPlanes\\\"]]],null]]],[8],[0,\\\"\\\\n          loadDrawingPlanes\\\\n        \\\"],[9],[0,\\\"\\\\n        \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"cut-controllers\\\"],[8],[0,\\\"\\\\n           \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"cut-controllers\\\"],[8],[0,\\\"\\\\n             \\\"],[7,\\\"input\\\",true],[10,\\\"id\\\",\\\"show-cut\\\"],[10,\\\"name\\\",\\\"show-cut\\\"],[10,\\\"checked\\\",\\\"\\\"],[10,\\\"type\\\",\\\"checkbox\\\"],[8],[9],[0,\\\"\\\\n             \\\"],[7,\\\"label\\\",true],[10,\\\"for\\\",\\\"show-cut\\\"],[8],[0,\\\"Show Cut\\\"],[9],[0,\\\"\\\\n           \\\"],[9],[0,\\\"\\\\n           \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"cut-controllers\\\"],[8],[0,\\\"\\\\n             \\\"],[7,\\\"input\\\",true],[10,\\\"id\\\",\\\"invert-cut\\\"],[10,\\\"name\\\",\\\"invert-cut\\\"],[10,\\\"type\\\",\\\"checkbox\\\"],[8],[9],[0,\\\"\\\\n             \\\"],[7,\\\"label\\\",true],[10,\\\"for\\\",\\\"invert-cut\\\"],[8],[0,\\\"Invert Cut\\\"],[9],[0,\\\"\\\\n           \\\"],[9],[0,\\\"\\\\n\\\\n           \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"cut-controllers\\\"],[8],[0,\\\"\\\\n             \\\"],[7,\\\"input\\\",true],[10,\\\"id\\\",\\\"cut-position-changer\\\"],[10,\\\"type\\\",\\\"range\\\"],[8],[9],[0,\\\"\\\\n           \\\"],[9],[0,\\\"\\\\n         \\\"],[9],[0,\\\"\\\\n      \\\"],[9],[0,\\\"\\\\n    \\\"],[9],[0,\\\"\\\\n\\\\n    \\\"],[7,\\\"div\\\",true],[10,\\\"id\\\",\\\"threedee\\\"],[10,\\\"class\\\",\\\"threedee\\\"],[8],[0,\\\"\\\\n      \\\"],[7,\\\"div\\\",true],[10,\\\"id\\\",\\\"threejs\\\"],[10,\\\"class\\\",\\\"\\\"],[8],[0,\\\"\\\\n\\\\n        \\\"],[1,[23,0,[\\\"threejsscene\\\"]],false],[0,\\\"\\\\n\\\\n      \\\"],[9],[0,\\\"\\\\n    \\\"],[9],[0,\\\"\\\\n\\\\n\\\\n    \\\"],[7,\\\"div\\\",true],[10,\\\"id\\\",\\\"screenshotPreviews\\\"],[8],[0,\\\"\\\\n\\\\n    \\\"],[9],[0,\\\"\\\\n\\\\n    \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"footer\\\"],[8],[0,\\\"\\\\n      \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"footerlinks\\\"],[8],[0,\\\"\\\\n         (c) SWG Engineering \\\"],[1,[23,0,[\\\"version\\\"]],false],[0,\\\"\\\\n      \\\"],[9],[0,\\\"\\\\n    \\\"],[9],[0,\\\"\\\\n\\\\n  \\\"],[9],[0,\\\"\\\\n\\\"]],\\\"hasEval\\\":false}\",\n    \"meta\": {\n      \"moduleName\": \"m08-2020/templates/application.hbs\"\n    }\n  });\n\n  _exports.default = _default;\n});","define(\"m08-2020/templates/components/custom-input\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  var _default = Ember.HTMLBars.template({\n    \"id\": \"QmJDY46m\",\n    \"block\": \"{\\\"symbols\\\":[\\\"&default\\\"],\\\"statements\\\":[[14,1],[0,\\\"\\\\n\\\"]],\\\"hasEval\\\":false}\",\n    \"meta\": {\n      \"moduleName\": \"m08-2020/templates/components/custom-input.hbs\"\n    }\n  });\n\n  _exports.default = _default;\n});","define(\"m08-2020/templates/components/file-picker\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n\n  var _default = Ember.HTMLBars.template({\n    \"id\": \"DtMFDMHF\",\n    \"block\": \"{\\\"symbols\\\":[\\\"&default\\\"],\\\"statements\\\":[[4,\\\"if\\\",[[24,[\\\"dropzone\\\"]]],null,{\\\"statements\\\":[[0,\\\"  \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"file-picker__dropzone\\\"],[8],[0,\\\"\\\\n    \\\"],[14,1],[0,\\\"\\\\n  \\\"],[9],[0,\\\"\\\\n\\\"]],\\\"parameters\\\":[]},{\\\"statements\\\":[[0,\\\"  \\\"],[14,1],[0,\\\"\\\\n\\\"]],\\\"parameters\\\":[]}],[0,\\\"\\\\n\\\"],[4,\\\"if\\\",[[24,[\\\"preview\\\"]]],null,{\\\"statements\\\":[[0,\\\"  \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"file-picker__preview\\\"],[8],[9],[0,\\\"\\\\n\\\"]],\\\"parameters\\\":[]},null],[0,\\\"\\\\n\\\"],[4,\\\"if\\\",[[24,[\\\"progress\\\"]]],null,{\\\"statements\\\":[[4,\\\"if\\\",[[24,[\\\"showProgress\\\"]]],null,{\\\"statements\\\":[[4,\\\"if\\\",[[24,[\\\"isProgressSupported\\\"]]],null,{\\\"statements\\\":[[0,\\\"      \\\"],[7,\\\"progress\\\",true],[11,\\\"value\\\",[22,\\\"progressValue\\\"]],[10,\\\"max\\\",\\\"100\\\"],[10,\\\"class\\\",\\\"file-picker__progress\\\"],[8],[1,[22,\\\"progress\\\"],false],[0,\\\" %\\\"],[9],[0,\\\"\\\\n\\\"]],\\\"parameters\\\":[]},{\\\"statements\\\":[[0,\\\"      \\\"],[7,\\\"div\\\",true],[10,\\\"class\\\",\\\"file-picker__progress\\\"],[8],[0,\\\"\\\\n        \\\"],[7,\\\"span\\\",true],[10,\\\"class\\\",\\\"file-picker__progress__value\\\"],[11,\\\"style\\\",[22,\\\"progressStyle\\\"]],[8],[9],[0,\\\"\\\\n      \\\"],[9],[0,\\\"\\\\n\\\"]],\\\"parameters\\\":[]}]],\\\"parameters\\\":[]},null]],\\\"parameters\\\":[]},null],[0,\\\"\\\\n\\\"],[1,[28,\\\"input\\\",null,[[\\\"type\\\",\\\"value\\\",\\\"accept\\\",\\\"multiple\\\",\\\"class\\\"],[\\\"file\\\",[24,[\\\"file\\\"]],[24,[\\\"accept\\\"]],[24,[\\\"multiple\\\"]],\\\"file-picker__input\\\"]]],false],[0,\\\"\\\\n\\\"]],\\\"hasEval\\\":false}\",\n    \"meta\": {\n      \"moduleName\": \"m08-2020/templates/components/file-picker.hbs\"\n    }\n  });\n\n  _exports.default = _default;\n});","define(\"m08-2020/transforms/boolean\", [\"exports\", \"@ember-data/serializer/-private\"], function (_exports, _private) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _private.BooleanTransform;\n    }\n  });\n});","define(\"m08-2020/transforms/date\", [\"exports\", \"@ember-data/serializer/-private\"], function (_exports, _private) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _private.DateTransform;\n    }\n  });\n});","define(\"m08-2020/transforms/number\", [\"exports\", \"@ember-data/serializer/-private\"], function (_exports, _private) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _private.NumberTransform;\n    }\n  });\n});","define(\"m08-2020/transforms/string\", [\"exports\", \"@ember-data/serializer/-private\"], function (_exports, _private) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _private.StringTransform;\n    }\n  });\n});","define(\"m08-2020/translations/en-us\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  var _default = {\n    \"price_banner\": \"The {product} costs {price, number, USD}\"\n  };\n  _exports.default = _default;\n});","define(\"m08-2020/utils/intl/missing-message\", [\"exports\", \"ember-intl/utils/missing-message\"], function (_exports, _missingMessage) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  Object.defineProperty(_exports, \"default\", {\n    enumerable: true,\n    get: function () {\n      return _missingMessage.default;\n    }\n  });\n});","\n","define('m08-2020/config/environment', [], function() {\n  var prefix = 'm08-2020';\ntry {\n  var metaName = prefix + '/config/environment';\n  var rawConfig = document.querySelector('meta[name=\"' + metaName + '\"]').getAttribute('content');\n  var config = JSON.parse(decodeURIComponent(rawConfig));\n\n  var exports = { 'default': config };\n\n  Object.defineProperty(exports, '__esModule', { value: true });\n\n  return exports;\n}\ncatch(err) {\n  throw new Error('Could not read config from meta tag with name \"' + metaName + '\".');\n}\n\n});\n","\n          if (!runningTests) {\n            require(\"m08-2020/app\")[\"default\"].create({\"name\":\"m08-2020\",\"version\":\"0.0.0+12abdbe6\",\"validatorDefaultLocale\":\"en\"});\n          }\n        \n"],"names":[],"mappings":"AAAA;AACA;AACA;;ACFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1gBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxiBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1zBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACllBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7zBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/mBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9TA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACx/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChiFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACthBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5zDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChkBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxgBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;","file":"m08-2020.js"}